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.

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

  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 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.
  • Create a dual boot mechanism, the fastest way to do this is installing the handy gem next_rails.

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

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.

3. Gems

If your application relies on MultiJSON, 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. You can use this task as a guideline as explained thoroughly in this post.

As an alternative, check out RailsDiff, 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</h2> - Return from callbacks is no longer allowed: Before: ``` before_save { return false } ``` After: ``` before_save { false } ``` See: [https://github.com/rails/rails/pull/13271](https://github.com/rails/rails/pull/13271)

b. ActiveRecord</h2> - 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](https://fastruby.io/blog/rails/upgrades/upgrade-rails-from-3-2-to-4-0.html) 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](https://github.com/rails/rails/commit/f950b2699f97749ef706c6939a84dfc85f0b05f2)) (Friendly reminder: beware when using [default_scope](https://www.ombulabs.com/blog/ruby/rails/best-practices/why-using-default-scope-is-a-bad-idea.html)) - 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](https://github.com/rails/rails/issues/9712)). 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](http://blog.ifyouseewendy.com/blog/2015/11/11/preload-eager_load-includes-references-joins/). 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

- [CSRF protection](http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf) now covers GET requests with JS responses: 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](https://github.com/rails/rails/pull/13345)

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](https://www.fastruby.io/).
Get the book