Upgrade Rails from 4.0 to 4.1

Upgrade Rails from 4.0 to 4.1

This article is part of our Upgrade Rails series. To see more of them, click here opens a new window .

This article will cover the most important aspects that you need to know to get your Ruby on Rails opens a new window application from version 4.0 opens a new window to 4.1 opens a new window .

  1. Preparations
  2. Ruby version
  3. Gems
  4. Config files (config/)
  5. Application code
  6. Callbacks
  7. ActiveRecord
  8. Tests
  9. Miscellaneous
  10. Next steps

1. Preparations

Before beginning with the upgrade process, we have some recommended preparations:

  • Your Rails app should have the latest patch version opens a new window before you move to the next major/minor version.
  • You should have at least 80% test coverage unless you have a dedicated QA team.
  • Follow a Git flow workflow to actively manage at least two environments: staging and production.
  • Check your Gemfile.lock for incompatibilities by using RailsBump opens a new window .
  • Create a dual boot mechanism, the fastest way to do this is installing the handy gem next_rails opens a new window .

For full details check out our article on How to Prepare Your App for a Rails Upgrade opens a new window .

2. Ruby version

Rails 4.1 requires Ruby 1.9.3 or later. Ruby 1.8.7 support was dropped in Rails 4.0, so you should already be running 1.9.3 or later. For Rails 4.1, Ruby 2.0 (or newer) is preferred according to the official upgrade guide opens a new window .

3. Gems

If your application relies on MultiJSON opens a new window , you will need to add the gem to your Gemfile (gem 'multi_json') if it’s not already there, since it was removed from Rails 4.1.

Alternatively, stop using MultiJSON and migrate your application to use to_json and JSON.parse.

4. Config files

Rails includes the rails:update task opens a new window . You can use this task as a guideline as explained thoroughly in this post opens a new window .

As an alternative, check out RailsDiff opens a new window , which provides an overview of the changes in a basic Rails app between 4.0 and 4.1 (or any other source/target versions).

5. Application code

a. Callbacks

  • Return from callbacks is no longer allowed:

Before:

before_save { return false }

After:

before_save { false }

See: https://github.com/rails/rails/pull/13271 opens a new window

b. ActiveRecord

  • Removal of deprecated finders:

activerecord-deprecated_finders (https://github.com/rails/activerecord-deprecated_finders) was removed as a dependency from Rails 4.1. From the gem’s README:

To migrate dynamic finders to Rails 4.1+:

find_all_by_... should become where(...).
find_last_by_... should become where(...).last.
scoped_by_... should become where(...).
find_or_initialize_by_... should become find_or_initialize_by(...).
find_or_create_by_... should become find_or_create_by(...).

If you can’t afford to upgrade the finders now, then add the gem back yourself into the Gemfile:

gem 'activerecord-deprecated_finders'

See our last upgrade post opens a new window for more information.

  • Default scopes are now chained to other scopes:

If you thought default scopes on models could be confusing, there’s even another (un?)expected twist to it:

class User < ActiveRecord::Base
  default_scope { where active: true }
  scope :inactive, -> { where active: false }

  # ...
end

# Rails < 4.1
> User.all
SELECT "users".* FROM "users" WHERE "users"."active" = 'true'

> User.inactive
SELECT "users".* FROM "users" WHERE "users"."active" = 'false'

# Rails >= 4.1:

> User.all
SELECT "users".* FROM "users" WHERE "users"."active" = 'true'

> User.inactive
SELECT "users".* FROM "users" WHERE "users"."active" = 'true'
AND "users"."active" = 'false'

If you depended on this behavior, you will need to work around it using unscoped, unscope or the new rewhere method (source opens a new window )

(Friendly reminder: beware when using default_scope opens a new window )

  • No more mutable methods on ActiveRecord relations:

ActiveRecord::Relation no longer has access to mutator methods like #map!, #delete_if or #compact!. If you need to use them, you will need to convert the Relation to an Array by calling #to_a first.

Before:

Project.where(title: 'Rails Upgrade').compact!

After:

projects = Project.where(name: 'Rails Upgrade').to_a
projects.compact!
  • Implicit joins are removed:

Before Rails 4.1, if you had this code:

Post.includes(:comments).where("comments.title = 'foo'")

ActiveRecord 4.0 would know to join posts and comments in the executed SQL, and it would work just fine.

However, Rails shouldn’t have to be smart and parse your where with a regular expression to figure out what tables you want to join, since it leads to bugs (for example: https://github.com/rails/rails/issues/9712 opens a new window ).

To fix this problem, you need to use an explicit join:

Post.joins(:comments).where("comments.title = 'foo'")

Unless your intention was to actually eager load the post’s comments. In that case, you can use the following syntax:

Post.eager_load(:comments).where("comments.title = 'foo'")

Or:

Post.includes(:comments).where("comments.title = 'foo'").references(:comments)

Both are equivalent and produce the same SQL.

For a more in depth explanation of the differences between joins, includes, references, eager_load and even preload, check out this post opens a new window .

Finally, if you get this deprecation warning:

DEPRECATION WARNING: Implicit join references were removed with Rails 4.1. Make sure to remove this configuration because it does nothing.

Just remove config.active_record.disable_implicit_join_references from your config files.

6. Tests

If your tests hit JS URLs, you’ll need to use xhr instead of get:

Before:

post :create, format: :js

After:

xhr :post, :create, format: :js

See: https://github.com/rails/rails/pull/13345 opens a new window

7. Miscellaneous

  • Flash message keys are strings now:

If you were using the flash hash or its keys and expected symbols, you will need to use strings now:

Before:

flash.to_hash.except(:notify)

After:

flash.to_hash.except("notify")

8. Next steps

If you successfully followed all of these steps, you should now be running Rails 4.1! Do you have any other tips? Share it with us in the comments section.

If you’re not on Rails 4.1 yet, we can help! Download our free eBook: The Complete Guide to Upgrade Rails opens a new window .

Get the book