Using Image as a Container in React Native

Adding a nice looking background to a screen makes an app visually appealing. It also makes the app look more sleek and elegant. Let us see how we can leverage this technique in React Native and add an image as a background.

We’ll need to create different sizes of the background image, which we’re going to use as a container. React Native will pick up appropriate image based on the device’s dimension (check Images guide for more information).

- login-background.png (375x667)
- login-background@2x.png (750x1134)
- login-background@3x.png (1125x2001)

Now we’ll use these images in our code as container.

//...
render() {
    return (
      <Image
        source={require('./images/login-background.png')}
        style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native!
        </Text>
        <Text style={styles.instructions}>
          To get started, edit index.ios.js
        </Text>
        <Text style={styles.instructions}>
          Press Cmd+R to reload,{'\n'}
          Cmd+D or shake for dev menu
        </Text>
      </Image>
    );
  }
//...

const styles = StyleSheet.create({
  container: {
    flex: 1,
    width: undefined,
    height: undefined,
    backgroundColor:'transparent',
    justifyContent: 'center',
    alignItems: 'center',
  },
});

We’ve intentionally left height and width of the image as undefined. This will let React Native take the size of the image from the image itself. This way, we can use Image component as View and add other components as a children to build UI. image as container in react native

Rails 5 - What's in it for me?

This blog is part of our Rails 5 series.

I recently did a webinar with Srijan on upcoming changes in Rails 5. In this webinar I discussed various features and additions coming up in Rails 5.

Major Features

Ruby 2.2.2+ dependency.

Action Cable.

API only apps.

Features for Development mode

Puma as default web server.

rails CLI over rake.

Restarting app using rails restart.

Enable caching using rails dev:cache.

Enhanced filtering of routes using rails routes -g

Evented file system monitor.

Features for Test mode

Test Runner.

Changes to controller tests.

Cache content forever using http_cache_forever.

Collection caching using ActiveRecord#cache_key.

Partials caching using multi_fetch_frgaments.

Caching in Action Mailer views.

Changes in Active Record

Introduction of ApplicationRecord.

ActiveRelation#or.

has_secure_token for generating secure tokens.

Versioned migrations for backward compatibility.

Changes in Active Support

Improvements to Date/Time.

Enumerable#pluck, Enumerable#without.

Change in behavior related to halting callback chains.

Rails 5 officially supports MariaDB

MariaDB is an open source fork of the MySQL database and it acts as a drop-in replacement for MySQL.

After the Oracle’s take over of MySQL there was some confusion about the future of MySQL. To remove any ambiguity about whether in future MySQL will remain free or not MariaDB was started .

Some of you might be wondering what advantages MariaDB offers over MySQL.Here is an article which lists 10 reasons to migrate to MariaDB from MySQL.

MariaDB is bundled as default on systems like Redhat’s RHEL 7+, Archlinux, Slackware and OpenBSD.

Some of the users of MariaDB are Google, Mozilla, Facebook and Wikipedia. Later we found out that Basecamp has already been using MariaDB for a while.

Active Record support for MariaDB

Recently, Ian Gilfillan from MariaDB Foundation sent a Pull Request to include MariaDB as part Rails Documentation.

Accepting that pull request means Rails is committing to supporting MariaDB along with MySQL, PostgreSQL and SQLite.

The tests revealed an issue related to micro-precision support on time column.

If a column has time field and if we search on that column then the search was failing for MariaDB.

time = ::Time.utc(2000, 1, 1, 12, 30, 0, 999999)
Task.create!(start: time)
Task.find_by(start: time) # => nil

In the above case we created a record. However query yielded no record.

Now let’s see why the query did not work for MariaDB.

MariaDB vs MySQL time column difference

First let’s examine the tasks table.

 mysql> desc tasks;
+--------+---------+------+-----+---------+----------------+
| Field  | Type    | Null | Key | Default | Extra          |
+--------+---------+------+-----+---------+----------------+
| id     | int(11) | NO   | PRI | NULL    | auto_increment |
| start  | time    | YES  |     | NULL    |                |
+--------+---------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

In the above case column start is of type time.

Let’s insert a record in tasks table.

mysq> INSERT INTO `tasks` (`start`) VALUES ('2000-01-01 12:30:00');

Now let’s query the table.

mysql> SELECT  `tasks`.* FROM `tasks` WHERE `tasks`.`start` = '2000-01-01 12:30:00' LIMIT 1;
Empty set (0.00 sec)

In the above case query is passing date part(2000-01-01) along with the time part(12:30:00) for column start and we did not get any result.

Now let’s query again but this time we will pass only the time part to the start column.

mysql> SELECT  `tasks`.* FROM `tasks` WHERE `tasks`.`start` = '12:30:00' LIMIT 1;
+----+----------+
| id | start    |
+----+----------+
|  1 | 12:30:00 |
+----+----------+
1 row in set (0.00 sec)

So while quering if we pass 2000-01-01 12:30:00 to a column which is of type time then MariaDB fails.

Passing 2000-01-01 12:30:00 to MySQL, PostgreSQL and SQLite will work fine. That’s because the adapters for those databases will drop the date part if date is passed in the query string.

For MariaDB similar action was needed and soon enough a Pull Request, to take care of this behaviour from Rails side, was landed. MariaDB is itself, working on supporting this behaviour now.

Summary

In summary Rails 5 officially supports MariaDB and MariaDB can now safely be used as an alternative to MySQL for Ruby on Rails Applications.

Changes to test controllers in Rails 5

This blog is part of our Rails 5 series.

In Rails 5, controller tests have undergone some major changes. In this blog post, we will walk through some of those changes.

ActionController::TestCase is dreprecated

In Rails 5, controller tests are generated with superclass ActionDispatch::IntegrationTest instead of ActionController::TestCase which is deprecated . It will be moved into a separate gem in Rails 5.1 .

Rails 5 will use ActionDispatch::IntegrationTest by default for generating scaffolds as well controller tests stubs.

Use URL instead of action name with request methods in Rails 5

In Rails 4.x, we pass controller action as shown below.

class ProductsControllerTest < ActionController::TestCase

  def test_index_response
    get :index
    assert_response :success
  end
end

But in Rails 5, controller tests expect to receive URL instead of action. Otherwise test will throw exception URI::InvalidURIError: bad URI.

class ProductsControllerTest < ActionDispatch::IntegrationTest

  def test_index
    get products_url
    assert_response :success
  end
end

If we are upgrading an older Rails 4.x app to Rails 5, which have test cases with superclass ActionController::TestCase, then they will continue to work as it is without requiring to change anything from above.

Deprecation of assigns and assert_template in controller tests

In Rails 4.x, we can test instance variables assigned in a controller action and which template a particular controller action renders using assigns and assert_template methods.

class ProductsControllerTest < ActionController::TestCase
  def test_index_template_rendered
    get :index
    assert_template :index
    assert_equal Product.all, assigns(:products)
  end
end

But in Rails 5, calling assert_template or assigns will throw an exception.

class ProductsControllerTest < ActionDispatch::IntegrationTest
  def test_index_template_rendered
    get products_url
    assert_template :index
    assert_equal Product.all, assigns(:products)
  end
end

# Throws exception
NoMethodError: assert_template has been extracted to a gem. To continue using it,
  add `gem 'rails-controller-testing'` to your Gemfile.

These two methods have now been removed from the core and moved to a separate gem rails-controller-testing. If we still want to use assert_template and assigns, then we can do this by adding this gem in our applications.

Reasons for removing assigns and assert_template

The idea behind the removal of these methods is that instance variables and which template is rendered in a controller action are internals of a controller, and controller tests should not care about them.

According to Rails team, controller tests should be more concerned about what is the result of that controller action like what cookies are set, or what HTTP code is set rather than testing of the internals of the controller. So, these methods are removed from the core.

Use of Keywords arguments in HTTP request methods in Rails 5

In Rails 4.x, we pass various arguments like params, flash messages and session variables to request method directly.

class ProductsControllerTest < ActionController::TestCase

  def test_show
    get :show, { id: user.id }, { notice: 'Welcome' }, { admin: user.admin? }
    assert_response :success
  end
end

Where { id: user.id } are params, { notice: 'Welcome' } is flash and { admin: user.admin? } is session.

This becomes confusing sometimes, as it is not clear which argument belongs to which part.

Now in Rails 5, request methods accept only keyword arguments.

class ProductsControllerTest < ActionDispatch::IntegrationTest

  def test_create
    post product_url, params: { product: { name: "FIFA" } }
    assert_response :success
  end
end

This makes it easier to understand what arguments are being passed.

When we pass arguments without keywords arguments, then Rails logs a deprecation warning.

class ProductsControllerTest < ActionDispatch::IntegrationTest

  def test_create
    post product_url, { product: { name: "FIFA" } }
    assert_response :success
  end
end

DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request methods will accept
only the following keyword arguments in future Rails versions:
params, headers, env, xhr

Rails 5 has added accessed_fields to find the fields that are actually being used in the application

This blog is part of our Rails 5 series.

Rails makes it very easy to select all the fields of a table.

@users = User.all

Above code is selecting all the columns of the table users. This might be ok in most cases. However in some cases we might want to select only certain columns for performance reason. The difficult task is finding what all columns are actually used in a request.

To help in this task, Rails 5 has added accessed_fields method which lists attributes that were actually used in the operation.

This is helpful in development mode in determining what all fields are really being used by the application.

class UsersController < ApplicationController
  def index
    @users = User.all
  end
end
# app/views/users/index.html.erb

<table>
  <tr>
    <th>Name</th>
    <th>Email</th>
  </tr>
  <% @users.each do |user| %>
    <tr>
      <td><%= user.name %></td>
      <td><%= user.email %></td>
    </tr>
  <% end %>

</table>

Now, in order to find all the fields that were actually used, let’s add after_action to the controller.

class UsersController < ApplicationController

  after_action :print_accessed_fields

  def index
    @users = User.all
  end

  private

  def print_accessed_fields
    p @users.first.accessed_fields
  end
end

Let’s take a look at the log file.

Processing by UsersController#index as HTML
  User Load (0.1ms) SELECT "users".* FROM "users"
  Rendered users/index.html.erb within layouts/application (1.0ms)
  ["name", "email"]

As we can see, it returns ["name", "email"] as attributes which were actually used.

If users table has 20 columns then we do not need to load values all those other columns. We are using only two columns. So let’s change code to reflect that.

class UsersController < ApplicationController
  def index
    @users = User.select(:name, :email)
  end
end

Rails 5 adds warning when fetching big result set with Active Record

This blog is part of our Rails 5 series.

With large data set we can run into memory issue. Here is an example.

>> Post.published.count
=> 25000

>> Post.where(published: true).each do |post|
     post.archive!
   end

# Loads 25000 posts in memory

Rails 5 adds warning when loading large data set

To mitigate issue shown above Rails 5 has added config.active_record.warn_on_records_fetched_greater_than.

When this configuration is set to an integer value, any query that returns the number of records greater than the set limit, logs a warning.

config.active_record.warn_on_records_fetched_greater_than = 1500

>> Post.where(published: true).each do |post|
     post.archive!
   end

=> Query fetched 25000 Post records: SELECT "posts".* FROM "posts" WHERE "posts"."published" = ? [["published", true]]
   [#<Post id: 1, title: 'Rails', user_id: 1, created_at: "2016-02-11 11:32:32", updated_at: "2016-02-11 11:32:32", published: true>, #<Post id: 2, title: 'Ruby', user_id: 2, created_at: "2016-02-11 11:36:05", updated_at: "2016-02-11 11:36:05", published: true>,....]

This helps us find areas where potential problems exist and then we can replace inefficient queries with better ones.

config.active_record.warn_on_records_fetched_greater_than = 1500

>> Post.where(published: true).find_each do |post|
     post.archive!
   end

# No warning is logged

Rails 5 allows to send log to STDOUT via environment variable

This blog is part of our Rails 5 series.

By default, Rails creates log directory in a file that is named after the environment in which the application is running. So in production environment, logs are by default directed to production.log file.

We will have to define custom loggers if these logs are to be directed to another file or to standard output. Presence of such custom logic is what enables Rails to direct logs to STDOUT along with development.log file in development environment.

Rails 5, however, supports logging to STDOUT in production environment through introduction of new environment variable RAILS_LOG_TO_STDOUT.

In a brand new Rails app, we can see the following snippet in production.rb file.

if ENV["RAILS_LOG_TO_STDOUT"].present?
  config.logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
end

By setting RAILS_LOG_TO_STDOUT to any value we should have the production logs directed to STDOUT.

We can see in the snippet above config.logger is overwritten. Therefore now the logs will not be directed to production.log file.

To opt out of this and revert to the original functionality, we can either assign a blank value to this environment constant or remove RAILS_LOG_TO_STDOUT from the list of environment constants.

Validate multiple contexts together in Rails 5

This blog is part of our Rails 5 series.

Active Record validation is a well-known and widely used functionality of Rails. Slightly lesser popular is Rails’s ability to validate on custom context.

If used properly, contextual validations can result in much cleaner code. To understand validation context, we will take example of a form which is submitted in multiple steps:

class MultiStepForm < ActiveRecord::Base
  validate :personal_info
  validate :education, on: :create
  validate :work_experience, on: :update
  validate :final_step, on: :submission

  def personal_info
    # validation logic goes here..
  end

  # Smiliary all the validation methods go here.
end

Let’s go through all the four validations one-by-one.

1. personal_info validation has no context defined (notice the absence of on:). Validations with no context are executed everytime a model save is triggered. Please go through all the triggers here.

2. education validation has context of :create. It is executed only when a new object is created.

3. work_experience validation is in :update context and gets triggered for updates only. :create and :update are the only two pre-defined contexts.

4. final_step is validated using a custom context named :submission. Unlike above scenarios, it needs to be explicitly triggered like this:

form = MultiStepForm.new

# Either
form.valid?(:submission)

# Or
form.save(context: :submission)

valid? runs the validation in given context and populates errors. save would first call valid? in the given context and persist the changes if validations pass. Otherwise populates errors.

One thing to note here is that when we validate using an explicit context, Rails bypasses all other contexts including :create and :update.

Now that we understand validation context, we can switch our focus to validate multiple context together enhancement in Rails 5.

Let’s change our contexts from above example to

class MultiStepForm < ActiveRecord::Base
  validate :personal_info, on: :personal_submission
  validate :education, on: :education_submission
  validate :work_experience, on: :work_ex_submission
  validate :final_step, on: :final_submission

  def personal_info
    # code goes here..
  end

  # Smiliary all the validation methods go here.
end

For each step, we would want to validate the model with all previous steps and avoid all future steps. Prior to Rails 5, this can be achieved like this:

class MultiStepForm < ActiveRecord::Base
  #...

  def save_personal_info
    self.save if self.valid?(:personal_submission)
  end

  def save_education
    self.save if self.valid?(:personal_submission)
              && self.valid?(:education_submission)
  end

  def save_work_experience
    self.save if self.valid?(:personal_submission)
              && self.valid?(:education_submission)
              && self.valid?(:work_ex_submission)
  end

  # And so on...
end

Notice that valid? takes only one context at a time. So we have to repeatedly call valid? for each context.

This gets simplified in Rails 5 by enhancing valid? and invalid? to accept an array. Our code changes to:

class MultiStepForm < ActiveRecord::Base
  #...

  def save_personal_info
    self.save if self.valid?(:personal_submission)
  end

  def save_education
    self.save if self.valid?([:personal_submission,
                              :education_submission])
  end

  def save_work_experience
    self.save if self.valid?([:personal_submission,
                              :education_submission,
                              :work_ex_submission])
  end
end

A tad bit cleaner I would say.

Rails 5 changes protect_from_forgery execution order

This blog is part of our Rails 5 series.

What makes Rails a great framework to work with is its sane conventions over configuration. Rails community is always striving to keep these conventions relevant over time. In this blog, we will see why and what changed in execution order of protect_from_forgery.

protect_from_forgery protects applications against CSRF. Follow that link to read up more about CSRF.

What

If we generate a brand new Rails application in Rails 4.x then application_controller will look like this.

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
end

Looking it at the code it does not look like protect_from_forgery is a before_action call but in reality that’s what it is. Since protect_from_forgery is a before_action call it should follow the order of how other before_action are executed. But this one is special in the sense that protect_from_forgery is executed first in the series of before_action no matter where protect_from_forgery is mentioned. Let’s see an example.

class ApplicationController < ActionController::Base
  before_action :load_user
  protect_from_forgery with: :exception
end

In the above case even though protect_from_forgery call is made after load_user, the protection execution happens first. And we can’t do anything about it. We can’t pass any option to stop Rails from doing this.

Rails 5 changes this behavior by introducting a boolean option called prepend. Default value of this option is false. What it means is, now protect_from_forgery gets executed in order of call. Of course, this can be overridden by passing prepend: true as shown below and now protection call will happen first just like Rails 4.x.

class ApplicationController < ActionController::Base
  before_action :load_user
  protect_from_forgery with: :exception, prepend: true
end

Why

There isn’t any real advantage in forcing protect_from_forgery to be the first filter in the chain of filters to be executed. On the flip side, there are cases where output of other before_action should decide the execution of protect_from_forgery. Let’s see an example.

class ApplicationController < ActionController::Base
  before_action :authenticate
  protect_from_forgery unless: -> { @authenticated_by.oauth? }

  private
    def authenticate
      if oauth_request?
        # authenticate with oauth
        @authenticated_by = 'oauth'.inquiry
      else
        # authenticate with cookies
        @authenticated_by = 'cookie'.inquiry
      end
    end
end

Above code would fail in Rails 4.x, as protect_from_forgery, though called after :authenticate, actually gets executed before it. Due to which we would not have @authenticated_by set properly.

Whereas in Rails 5, protect_from_forgery gets executed after :authenticate and gets skipped if authentication is oauth.

Upgrading to Rails 5

Let’s take an example to understand how this change might affect the upgradation of applications from Rails 4 to Rails 5.

class ApplicationController < ActionController::Base
  before_action :set_access_time
  protect_from_forgery

  private
    def set_access_time
      current_user.access_time = Time.now
      current_user.save
    end
end

In Rails 4.x, set_access_time is not executed for bad requests. But it gets executed in Rails 5 because protect_from_forgery is called after set_access_time.

Saving data (current_user.save) in before_action is anyways a big enough violation of the best practices, but now those persistences would leave us vulnerable to CSRF if they are called before protect_from_forgery is called.

Rails 5 provides application config to use UUID as primary key

This blog is part of our Rails 5 series.

UUIDs are a popular alternative to auto-incremental integer primary keys.

create_table :users, id: :uuid do |t|
  t.string :name
end

Notice that id: :uuid is passed to create_table. This is all we need to do to have UUID as primary key for users.

Now, if an application is designed to use UUID instead of Integer, then chances are that new tables too would use UUID as primary key. And it can easily get repetitive to add id: :uuid in create_table , everytime a new model is generated.

Rails 5 comes up with a solution. We need to set primary key as UUID in config/application.rb.

config.active_record.primary_key = :uuid

This automatically adds id: :uuid to create_table in all future migrations.

One small recurrence off our plate.

Rails 5 changed Active Job default adapter from Inline to Async

This blog is part of our Rails 5 series.

Active Job has built-in adapters for multiple queuing backends among which two are intended for development and testing. They are Active Job Inline Adapter and Active Job Async Adapter.

These adapters can be configured as follows.

# for Active Job Inline
Rails.application.config.active_job.queue_adapter = :inline

# for Active Job Async
Rails.application.config.active_job.queue_adapter = :async

In Rails 4.x the default queue adapter is :inline. In Rails 5 it has been changed to :async by DHH.

Asynchronous Execution

In case of inline, as the name suggests, execution of the job happens in the same process that invokes the job. In case of Async adapter, the job is executed asynchronously using in-process thread pool.

AsyncJob makes use of a concurrent-ruby thread pool and the data is retained in memory. Since the data is stored in memory, if the application restarts, this data is lost. Hence, AsyncJob should not be used in production.

Running in future

AsyncJob supports running the job at some time in future through perform_later. Inline executes the job immediately and does not support running the job in future.

Both Active Job Async and Active Job Inline do not support configuring priorities among queues, timeout in execution and retry intervals/counts.

Advantage of having Async as default adapter

In Rails 4.x where Inline is the default adapter, the test cases were mistakenly dependent on job’s behavior that happens synchronously in development/testing environment. Using Async adapter ,by default, will help users have tests not rely on such synchronous behavior.

It’s a step closer to simulating your production environment where jobs are executed asynchronously with more persistent backends.

Consider an example, where in an e-commerce site upon every order placed an email is sent.

test "order is created successfully" do
  # Code to test record in orders table is created
end

test "order email is sent" do
  # Code to test order email is sent
end

The process of sending email can be part of a job which is invoked from an after_create callback in Order model.

class Order < ActiveRecord::Base

  after_create :send_order_email

  def send_order_email
    # Invoke the job of sending an email asynchronously.
  end

end

When Inline adapter is used, any wrongly configurated email settings will cause both the above tests to fail. This is because the process of sending the email happens within the process of order creation and any error in sending the email would kill the process if unhandled.

Support for left outer join in Rails 5

This blog is part of our Rails 5 series.

Suppose in a blog application there are authors and posts. A post belongs to an author, while author has many posts.

The app needs to show a list of all the authors along with a number of posts that they have written.

For this, we need to join author and posts table with “left outer join”. More about “left outer join” here, here and here .

In Rails 4.x, we need to write the SQL for left outer join manually as Active Record does not have support for outer joins.

authors = Author.join('LEFT OUTER JOIN "posts" ON "posts"."author_id" = "authors"."id"')
                .uniq
                .select("authors.*, COUNT(posts.*) as posts_count")
                .group("authors.id")

Rails 5 has added left_outer_joins method.

authors = Author.left_outer_joins(:posts)
                .uniq
                .select("authors.*, COUNT(posts.*) as posts_count")
                .group("authors.id")

It also allows to perform the left join on multiple tables at the same time.

>> Author.left_joins :posts, :comments
  Author Load (0.1ms)  SELECT "authors".* FROM "authors" LEFT OUTER JOIN "posts" ON "posts"."author_id" = "authors"."id" LEFT OUTER JOIN "comments" ON "comments"."author_id" = "authors"."id"

If you feel left_outer_joins is too long to type, then Rails 5 also has an alias method left_joins.

has_secure_token to generate unique random token in Rails 5

This blog is part of our Rails 5 series.

We sometimes need unique and random tokens in our web apps. Here is how we typically build it.

class User < ActiveRecord::Base

  before_create :set_access_token

  private

  def set_access_token
    self.access_token = generate_token
  end

  def generate_token
    loop do
      token = SecureRandom.hex(10)
      break token unless User.where(access_token: token).exists?
    end
  end
end

has_secure_token in Rails 5

Rails 5 has added has_secure_token method to generate a random alphanumeric token for a given column.

class User < ApplicationRecord
  has_secure_token
end

By default, Rails assumes that the attribute name is token. We can provide a different name as a parameter to has_secure_token if the attribute name is not token.

class User < ApplicationRecord
  has_secure_token :password_reset_token
end

The above code assumes that we already have password_reset_token attribute in our model.

>> user = User.new
>> user.save
=> true

>> user.password_reset_token
=> 'qjCbex522DfVEVd5ysUWppWQ'

The generated tokens are URL safe and are of fixed length strings.

Migration helper for generating token

We can also generate migration for token similar to other data types.

$ rails g migration add_auth_token_to_user auth_token:token
class AddAuthTokenToUser < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :auth_token, :string
    add_index :users, :auth_token, unique: true
  end
end

Notice that migration automatically adds index on the generated column with unique constraint.

We can also generate a model with the token attribute.

$ rails g model Product access_token:token
class CreateProducts < ActiveRecord::Migration[5.0]
  def change
    create_table :products do |t|
      t.string :access_token

      t.timestamps
    end
    add_index :products, :access_token, unique: true
  end
end

Model generator also adds has_secure_token method to the model.

class Product < ApplicationRecord
  has_secure_token :access_token
end

Regenerating tokens

Sometimes we need to regenerate the tokens based on some expiration criteria.

In order to do that, we can simply call regenerate_#{token_attribute_name} which would regenerate the token and save it to its respective attribute.

>> user = User.first
=> <User id: 11, name: 'John', email: 'john@example.com',
         token: "jRMcN645BQyDr67yHR3qjsJF",
         password_reset_token: "qjCbex522DfVEVd5ysUWppWQ">

>> user.password_reset_token
=> "qjCbex522DfVEVd5ysUWppWQ"

>> user.regenerate_password_reset_token
=> true

>> user.password_reset_token
=> "tYYVjnCEd1LAXvmLCyyQFzbm"

Beware of race condition

It is possible to generate a race condition in the database while generating the tokens. So it is advisable to add a unique index in the database to deal with this unlikely scenario.

Suppress save events in Rails 5

This blog is part of our Rails 5 series.

Rails 5 added suppress method which is used to prevent the receiver from being saved during the given block.

Use case for suppress method

Let’s say, we have an E-commerce application, which has many products. Whenever new product is launched then subscribed customers are notified about it.

class Product < ApplicationRecord
  has_many :notifications
  belongs_to :seller

  after_save :send_notification

  def launch!
    update_attributes!(launched: true)
  end

  private

  def send_notification
    notifications.create(message: 'New product Launched', seller: seller)
  end
end

class Notification < ApplicationRecord
  belongs_to :product
  belongs_to :seller

  after_create :send_notifications

  private

  def send_notifications
    # Sends notification about product to customers.
  end
end

class Seller < ApplicationRecord
  has_many :products
end

This creates a notification record every time we launch a product.

>> Notification.count
=> 0

>> seller = Seller.last
=> <Seller id: 6, name: "John">

>> product = seller.products.create(name: 'baseball hat')
=> <Product id: 4, name: "baseball hat", seller_id: 6>

>> product.launch!

>> Notification.count
=> 1

Now, we have a situation where we need to launch a product but we don’t want to send notifications about it.

Before Rails 5, this was possible only by adding more conditions.

ActiveRecord::Base.Suppress in Rails 5

In Rails 5, we can use ActiveRecord::Base.suppress method to suppress creating of notifications as shown below.

class Product < ApplicationRecord
  def launch_without_notifications
    Notification.suppress do
      launch!
    end
  end
end

>> Notification.count
=> 0

>> product = Product.create!(name: 'tennis hat')
=> <Event id: 1, name: "tennis hat">

>> product.launch_without_notifications

>> Notification.count
=> 0

As we can see, no new notifications were created when product is launched inside Notification.suppress block.

Checkout the pull request to gain better understanding of how suppress works.

Rails 5 makes rendering partial from cache substantially faster

This blog is part of our Rails 5 series.

Let’s have a look at Rails view code that renders partial using a collection.

# index.html.erb
<%= render partial: 'todo', collection: @todos %>

# _todo.html.erb
<% cache todo do %>
  <%= todo.name %>
<% end %>

In the above case Rails will do one fetch from the cache for each todo.

Fetch is usually pretty fast with any caching solution, however, one fetch per todo can make the app slow.

Gem multi_fetch_fragments fixed this issue by using read_multi api provided by Rails.

In a single call to cache, this gem fetches all the cache fragments for a collection. The author of the gem saw 78% speed improvement by using this gem.

The features of this gem have been folded into Rails 5.

To get benefits of collection caching, just add cached: true as shown below.

# index.html.erb
<%= render partial: 'todo', collection: @todos, cached: true %>

# _todo.html.erb
<% cache todo do %>
  <%= todo.name %>
<% end %>

With cached: true present, Rails will use read_multi to the cache store instead of reading from it every partial.

Rails will also log cache hits in the logs as below.

  Rendered collection of todos/_todo.html.erb [100 / 100 cache hits] (339.5ms)

Checkout the pull request to gain better understanding about how collection caching works.

Rails 5 switches from strong etags to weak etags

This blog is part of our Rails 5 series.

ETag, short for entity tag, is a part of HTTP header and is used for web cache validation. ETag is a digest of the resource that uniquely identifies specific version of the resource. This helps browser and web servers determine if resource in the browser’s cache is exactly same as the resource on the server.

Strong v/s Weak ETags

ETag supports strong and weak validation of the resource.

Strong ETag indicates that resource content is same for response body and the response headers.

Weak ETag indicates that the two representations are semantically equivalent. It compares only the response body.

Weak ETags are prefixed with W\ and thus one can easily distinguish between Weak ETags and Strong ETags.

"543b39c23d8d34c232b457297d38ad99"    – Strong ETag
W/"543b39c23d8d34c232b457297d38ad99"  – Weak ETag

W3 has an example page to illustrate how ETag matching works.

When server receives a request, it returns an ETag header as part of HTTP response. This ETag represents state of the resource. For the subsequent HTTP requests, client sends this ETag via If-None-Match header to identify if the resource is changed or not. The server will compare the current ETag and the one sent by the client. If ETag matches, server responds with 304 Not modified. This means resource content in the client’s cache is uptodate. If resource is changed, server will send updated resource along with the new ETag.

Let’s see it in action.

ETags in Rails 4.x

Rails 4.x generates strong ETags by default i.e without W/ prefix.

class ItemsController < ApplicationController
  def show
    @item = Item.find(params[:id])
    fresh_when @item
  end
end

We are making first request to the server.

$ curl -i http://localhost:3000/items/1

HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Etag: "618bbc92e2d35ea1945008b42799b0e7"
Last-Modified: Sat, 30 Jan 2016 08:02:12 GMT
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 98359119-14ae-4e4e-8174-708abbc3fd4b
X-Runtime: 0.412232
Server: WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)
Date: Fri, 04 Mar 2016 10:50:38 GMT
Content-Length: 1014
Connection: Keep-Alive

For the next request, we will send ETag that was sent by the sever. And notice that server returns 304 Not Modified.

$ curl -i -H 'If-None-Match: "618bbc92e2d35ea1945008b42799b0e7"' http://localhost:3000/items/1

HTTP/1.1 304 Not Modified
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Etag: "618bbc92e2d35ea1945008b42799b0e7"
Last-Modified: Sat, 30 Jan 2016 08:02:12 GMT
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: e4447f82-b96c-4482-a5ff-4f5003910c18
X-Runtime: 0.012878
Server: WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)
Date: Fri, 04 Mar 2016 10:51:22 GMT
Connection: Keep-Alive

Rails 5 sets Weak ETags by default

In Rails 5, all ETags generated by Rails will be weak by default.

$ curl -i http://localhost:3000/items/1

HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Etag: W/"b749c4dd1b20885128f9d9a1a8ba70b6"
Last-Modified: Sat, 05 Mar 2016 00:00:00 GMT
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: a24b986c-74f0-4e23-9b1d-0b52cb3ef906
X-Runtime: 0.038372
Server: WEBrick/1.3.1 (Ruby/2.2.3/2015-08-18)
Date: Fri, 04 Mar 2016 10:48:35 GMT
Content-Length: 1906
Connection: Keep-Alive

Now for the second request, server will return 304 Not Modified response as before, but the ETag is weak ETag.

$ curl -i -H 'If-None-Match: W/"b749c4dd1b20885128f9d9a1a8ba70b6"' http://localhost:3000/items/1

HTTP/1.1 304 Not Modified
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Etag: W/"b749c4dd1b20885128f9d9a1a8ba70b6"
Last-Modified: Sat, 05 Mar 2016 00:00:00 GMT
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 7fc8a8b9-c7ff-4600-bf9b-c847201973cc
X-Runtime: 0.005469
Server: WEBrick/1.3.1 (Ruby/2.2.3/2015-08-18)
Date: Fri, 04 Mar 2016 10:49:27 GMT
Connection: Keep-Alive

Why this change?

Rails does not perform strong validation of ETags as implied by strong ETags spec. Rails just checks whether the incoming ETag from the request headers matches with the ETag of the generated response. It does not do byte by byte comparison of the response.

This was true even before Rails 5. So this change is more of a course correction. Rack also generates weak ETags by default because of similar reasons.

Mark Notthingham is chair of HTTP Working Group and he has written about etags which has some useful links to other ETag resources.

Parameter filtering enhancement in Rails 5

This blog is part of our Rails 5 series.

For security reasons, we do not want sensitive data like passwords, credit card information, auth keys etc to appear in log files.

Rails makes it very easy to filter such data. Just add following line in application.rb to filter senstive information.

config.filter_parameters += [:password]

Now the log file will show [FILTERED] instead of real password value.

This replacement of password with [FILTERED] is done recursively.

{user_name: "john", password: "123"}
{user: {name: "john", password: "123"}}
{user: {auth: {id: "john", password: "123"}}}

In all the above cases, “123” would be replaced by “[FILTERED]”.

Now think of a situation where we do not want to filter all the occurrence of a key. Here is an example.

{credit_card: {number: "123456789", code: "999"}}
{user_preference: {color: {name: "Grey", code: "999999"}}}

We definitely want to filter [:credit_card][:code] but we want [:color][:code] to show up in the log file.

This can be achieved in Rails 5.

The application.rb changes from

config.filter_parameters += ["code"]

to

config.filter_parameters += ["credit_card.code"]

In this case so long as parent of code is credit_card Rails will filter the data.

Rails 5 adds http_cache_forever to allow caching of response forever

This blog is part of our Rails 5 series.

Rails 5 allows to cache HTTP responses forever by introducting http_cache_forever method.

Sometimes, we have static pages that never/rarely change.

# app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    render
  end
end

# app/views/home/index.html.erb
<h1>Welcome</h1>

Let’s see log for the above action.

Processing by HomeController#index as HTML
  Rendered home/index.html.erb within layouts/application (1.3ms)
Completed 200 OK in 224ms (Views: 212.4ms | ActiveRecord: 0.0ms)

 And so on for every request for this action.

There is no change in the response and still we are rendering same thing again and again and again.

Rails 5 introduces http_cache_forever

When response does not change then we want browsers and proxies to cache it for a long time.

Method http_cache_forever allows us to set response headers to tell broswers and proxies that response has not modified.

# app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
    http_cache_forever(public: true) {}
  end
end

# OR
class HomeController < ApplicationController
  def index
    http_cache_forever(public: true) do
      render
    end
  end
end


# app/views/home/index.html.erb
<h1>Welcome</h1>

Now let’s look at the log for the modified code.

# When request is made for the first time.

Processing by HomeController#index as HTML
  Rendered home/index.html.erb within layouts/application (1.3ms)
Completed 200 OK in 224ms (Views: 212.4ms | ActiveRecord: 0.0ms)

# For consecutive requests for the same page

Processing by HomeController#index as HTML
Completed 304 Not Modified in 2ms (ActiveRecord: 0.0ms)

On first hit, we serve the request normally but, then on each subsequent request cache is revalidated and a “304 Not Modified” response is sent to the browser.

Options with http_cache_forever

By default, HTTP responses are cached only on the user’s web browser. To allow proxies to cache the response, we can set public to true to indicate that they can serve the cached response.

Use http_cache_forever with caution

By using this method, Cache-Control: max-age=3155760000 is set as response header and browser/proxy won’t revalidate the resource back to the server unless force reload is done.

In case force reload is done, Cache-Control: max-age=0 is set as request header.

In this case, browser will receive the changed resource whether ETag is changed or not.

http_cache_forever is literally going to set the headers to cache it for 100 years and developers would have to take extra steps to revalidate it. So, this should be used with extra care.

Better exception responses in Rails 5 API apps

This blog post is part of our Rails 5 series.

Rails 4.x returns error information in HTML page whenever there is any exception, in the development environment.

This is fine for normal HTML requests. But traditionally, Rails always returned with HTML response for exceptions for all requests, including JSON on XML requests in development.

We can now generate API only apps in Rails 5. In case of such apps, it’s better to have the error message in the format in which request was made. Having an HTML response for a JSON endpoint like http://localhost:3000/posts.json is not going to help in debugging why the exception happened.

New config option debug_exception_response_format

Rails 5 has introduced new configuration to respond with proper format for exceptions.

# config/environments/development.rb
config.debug_exception_response_format = :api

Let’s see an example of the response received with this configuration.

$ curl localhost:3000/posts.json
{"status":404,"error":"Not Found","exception":"#\u003cActionController::RoutingError: No route matches [GET] \"/posts.json\"\u003e","traces":{"Application Trace":[...],"Framework Trace":[...]}}

The status key will represnt HTTP status code and error key will represent the corresponding Rack HTTP status.

exception will print the output of actual exception in inspect format.

traces will contain application and framework traces similar to how they are displayed in HTML error page.

By default, config.debug_exception_response_format is set to :api so as to render responses in the same format as requests.

If you want the original behavior of renndering HTML pages, you can configure this option as follows.

# config/environments/development.rb
config.debug_exception_response_format = :default

Use file_fixture to access test files in Rails 5

This blog is part of our Rails 5 series.

While writing tests sometimes we need to read files to compare the output. For example a test might want to compare the API response with pre determined data stored in a file.

Here is an example.

# In test helper
def file_data(name)
  File.read(Rails.root.to_s + "/tests/support/files/#{name}")
end

# In test
class PostsControllerTest < ActionDispatch::IntegrationTest
  setup do
    @post = posts(:one)
  end

  test "should get index" do
    get posts_url, format: :json

    assert_equal file_data('posts.json'), response.body
  end
end

File Fixtures in Rails 5

In Rails 5, we can now organize such test files as fixtures.

Newly generated Rails 5 applications, will have directory test/fixtures/files to store such test files.

These test files can be accessed using file_fixture helper method in tests.

require 'test_helper'

class PostsControllerTest < ActionDispatch::IntegrationTest
  setup do
    @post = posts(:one)
  end

  test "should get index" do
    get posts_url, format: :json

    assert_equal response.body, file_fixture('posts.json').read
  end
end

The file_fixture method returns Pathname object, so it’s easy to extract file specific information.

file_fixture('posts.json').read
file_fixture('song.mp3').size