Onwards to Rails 5: Additions, Changes, and Deprecations

chebyte
Hashdog Blog
Published in
6 min readMar 10, 2016

Rails 5, a new major release of the popular web framework, is coming soon and, of course, we are looking forward to it. Refer to this article if you want to read on overview of some new features that will be introduced. Today, however, we are going to dig into some technical details, discuss which methods were removed or deprecated, which settings have been changed, and how to migrate your existing Rails 4 application to version 5.

Don’t forget that after the release of Rails 5, all bug fixes will only be introduced for Rails 5.0.x, whereas regular security fixes will be applied to Rails 4.2.x, as stated in the official maintenance policy.

The source code for this app is available at GitHub.

Preparations

The first thing to take into consideration before proceeding is that Rails 5 requires Ruby 2.2.2 or higher, so if you don’t have this version installed, go ahead and download it now.

Before migrating your existing application to Rails 5, I really recommend you having a solid test suite, otherwise the migration process may become much more complex and painful. For this article I will be using a demo application, called MusicalShop, that was introduced in my screencast series RSpec with Rails. This is a very simple Rails 4 app, but it does have automated tests written in RSpec. You can clone the latest version of the app from this branch.

Also it is advised to migrate to the latest patch version of Rails 4 (which is currently 4.2.5.1). Additionally, you may check that the latest possible versions of gems are used in your project by running

$ bundle outdated

Be careful, though, not to introduce any conflicts by explicitly requiring the latest versions for all your gems (especially for dependencies).

Another thing to consider is some gems may not yet be compatible with Rails 5, so be prepared for that. Browse gem’s dependencies and skim through open issues on GitHub to find out whether other developers are facing problems while using the library with Rails 5. Some gems (like Devise, for example) may need to be included directly from the master branch.

Okay, so go ahead and check that the tests are running successfully:

$ rspec .

Don’t forget that, as Edsger Dijkstra said, “testing can never demonstrate the absence of errors in software, only their presence”. But we’ll hope for the best.

The last thing to do is to switch to another branch so that you can always return to an older version if things don’t go as planned:

$ git checkout -b rails5

Migrating

Take a deep breath and modify your Gemfile:

Gemfile

[...] gem 'rails', '>= 5.0.0.beta3', '< 5.1' [...]

Currently Rails is in beta, but a release candidate should be published pretty soon.

Run

$ bundle update

You may also run

$ rake rails:update

which creates the new files introduced in Rails 5, as well as, modifies the old ones.

All in all, Rails 5 configuration files are very similar to Rails 4, so chances are that you’ll be able to boot your app right away while seeing some deprecation messages. Some of you may remember that the migration process from Rails 3 to 4 was much more painful.

Still, many deprecated methods were removed, so if you were using any of them, you’ll have to modify the code base accordingly. Let’s discuss the major changes so that you understand which parts of the app will most require your attention.

Controllers

Okay, first of all, let’s observe changes that relate to controllers.

  • The skip_action_callback method is removed completely.
  • The :nothing option for the render method is deprecated.
  • The *_filter methods (before_filter, for example) are still supported, but deprecated and will be removed in Rails 5.1. Use *_action instead.
  • A nice method redirect_back is being introduced in favor of redirect_to :back. It tries to redirect to an HTTP_REFERER or to the provided location, so you may use it inside your methods:
redirect_back root_path
  • render :text is deprecated, as it does not render a text/plain response. Use render :plain instead or render :html to display a text/html page:
render plain: 'My text'

Views

Every form now has its own CSRF token by default. This is to prevent form hijacking when an attacker injects his own form on the page pointing to some malicious website.

Create an initializer file to control this behavior globally:

config/initializers/per_form_csrf_tokens.rb

Rails.application.config.action_controller.per_form_csrf_tokens = true

Or use the following setting inside individual controllers:

self.per_form_csrf_tokens = true

content_tag_for and div_for methods were removed from ActionView and extracted to the recordtaghelper gem.

Models

Rails 5 introduces a new abstract class (meaning, that it cannot be instantiated) called ApplicationRecord and all models inherit from it by default rather than from ActiveRecord::Base. This is done to prevent monkey-patching ActiveRecord::Base directly. So, you can introduce all extensions inside ApplicationRecord. If you want to employ this functionality, create application_record.rb file inside your models directory:

models/application_record.rb

class ApplicationRecord < ActiveRecord::Base self.abstract_class = true end

Next ensure that all models inherit from this new class, for example:

models/user.rb

class User < ApplicationRecord [...] end

Another addition is related to belongs_to associations: in Rails 5, the associated record must be present by default. The required option is now deprecated and a new optional parameter is being introduced. This means that, by default, Rails validates that the “parent” record is present before saving the object. If you do not wish to employ this behavior for some association, use

belongs_to :some_parent, optional: true

Rails 5 also comes with a activerecordbelongstorequiredbydefault.rb initializer file that controls this behavior for the whole application. You may create it as well:

config/initializers/active_record_belongs_to_required_by_default.rb

Rails.application.config.active_record.belongs_to_required_by_default = true

before_* callbacks that return false inside your models do not halt the callback chain anymore. If you wish to explicitly halt the callback chain, use throw(:abort) instead:

def my_callback throw(:abort) if something_bad_happened end

New Rails 5 apps comes with a callback_terminator.rb initializer file that controls this behavior:

config/inititalizers/callback_terminator.rb

ActiveSupport.halt_callback_chains_on_return_false = false

Another important thing to remember is that Rails 5 only works with PostgreSQL 9.1 and above.

Cache

Caching management in development was made more convenient. In Rails 4, we used to have the config.action_controller.perform_caching setting that accepts either true or false. In Rails 5, however, the following code snippet is now present:

config/environments/development.rb

[...] if Rails.root.join('tmp/caching-dev.txt').exist? config.action_controller.perform_caching = true config.cache_store = :memory_store config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=172800' } else config.action_controller.perform_caching = false config.cache_store = :null_store end [...]

To enable or disable caching, you can run the rake dev:cache command that creates caching-dev.txt file inside the tmp directory.

Routing

Multiple root routes may exist in the same scope now (previously, an error was raised). You can provide constraints and choose which root to use:

root 'blog#show', constraints: ->(req) { some_condition } root 'pages#show'

The rails routes command now accepts the following options to
search for specific routes:

  • -c returns all routes for the specified controller
  • -g returns routes based on the specified pattern

Tests

ActionController::TestCase HTTP request methods like get and post are deprecated. You should use process instead. For example, in my tests I have calls like:

spec/controllers/albums_controller_spec.rb

[...] get :index [...] post :create, album: {title: ''} [...]

These should be re-written as

spec/controllers/albums_controller_spec.rb

[...] process :index, method: :get [...] process :create, method: :post, params: { album: {title: ''} } [...]

The assigns and assert_template methods have been extracted to a separate rails-controller-testing gem. Add it into your Gemfile:

Gemfile

[...] group :test do gem 'rails-controller-testing' end [...]

If you are using RSpec like me, add the following lines into your rails_helper.rb file as a temporary fix (RSpec does not support Rails 5 officially yet):

spec/rails_helper.rb

[...] RSpec.configure do |config| config.include Rails::Controller::Testing::TestProcess config.include Rails::Controller::Testing::TemplateAssertions config.include Rails::Controller::Testing::Integration [...] end

Some Other Stuff

Another cool feature of Rails 5 is that all rake commands now live in rails (for example, rake db:migrate becomes rails db:migrate).

ActiveRecord::Base.raise_in_transactional_callbacks setting is deprecated and has no effect. It will be removed without replacement, so you can safely delete it from config/application.rb file.

ActiveJob now inherits from an intermediate ApplicationJob class. Create an application_job.rb file inside the jobs directory:

jobs/application_job.rb

class ApplicationJob < ActiveJob::Base end

Make sure that your jobs inherit from ApplicationJob.

ActionDispatch::Static accepts custom HTTP headers, so you may specify custom cache-control options.

The last thing to note is that ActionCable does not require Redis, EventMachine, and Celluloid to be present anymore.

Conclusion

So, Rails 5 promises a great set of new features and additions and I really encourage you to give it a try. Also, be sure to browse the complete changelog.

Are you planning to migrate to Rails 5 in the nearest future? How many of your apps are still running Rails 3 (or even Rails 2)? Share your opinion in the comments!

Originally published at www.sitepoint.com on March 10, 2016.

--

--