Ruby
How to upgrade to Rails 5
Rails 5 has a ton of new features. It addresses almost 500 issues and pull-requests dealing with performance, security and new features. I'm going to list step by step what you will need to migrate from Rails 4.2 to Rails 5.0.
How to upgrade from Rails 4.2 to Rails 5.0
1 - Update ruby
Rails 5 now requires Ruby 2.2.2 or greater. I suggest installing the latest:
- rbenv
rbenv install 2.3.1
- rvm
rvm install 2.3.1
2 - Update your gem dependencies to Rails 5
Change Rails version in your Gemfile
:
gem 'rails', '>= 5.0.0.rc2', '< 5.1'
Update Rails dependencies:
bundle update rails
You also might need to update some gems. Hopefully you have a nice test suite to rely on; this makes upgrading much smoother. So for each gem you have problems with, go to their documentation and check if they have any guidance for the upgrade.
3 - Update Rails binaries and configurations
Run the following for updating in a interactive mode your files in bin/
and /config
:
rails app:update
4 - Generate the db/schema.rb file again
There are changes to the db/schema.rb
file. For instance, Rails moved foreign and unique indexes to inside the create_table
methods. You don't even need to have a pending migration to generate a new schema.
rails db:migrate
5 - Application classes
Rails 5 has new application classes that you should have and inherit from, the same way as ApplicationController
or ApplicationHelper
:
ApplicationRecord
ApplicationMailer
ApplicationJob
5.1 - ApplicationRecord
Create your ApplicationRecord
:
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
Change your models to inherit from your new ApplicationRecord
:
# app/models/car.rb
class Car < ApplicationRecord
belongs_to :person
end
5.2 - ApplicationMailer
Create your ApplicationMailer
:
# app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
default from: 'from@example.com'
layout 'mailer'
end
At this point you may not have your mailer layout. Create one if not:
# app/views/layouts/mailer.html.erb
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>/* Email styles need to be inline */</style>
</head>
<body><%= yield %></body>
</html>
# app/views/layouts/mailer.text.erb
<%= yield %>
Then change your mailers to inherit from your new ApplicationMailer
.
5.3 - ApplicationJob
Create your ApplicationJob
:
# app/jobs/application_job.rb
class ApplicationJob < ActiveJob::Base
end
Change your jobs to inherit from your new ApplicationJob
.
6 - Validation changes on Belongs To relations
Rails 5 has changed the belongs_to
relation to require presence by default. Check the PR
So now required: true
is deprecated:
belongs_to :company, required: true # deprecated => `required: true`
You should create an initializer to explicitly configure the new behavior for the app:
#config/initializers/active_record_belongs_to_required_by_default.rb
Rails.application.config.active_record.belongs_to_required_by_default = true
And for every belongs_to
relation that is not required, just add optional: true
.
belongs_to :company, optional: true
7 - Halt callback chain - throw(:abort)
Active Record or Active Model callbacks no longer halt when returning false
. Check the PR
You should create another initializer to explicitly configure this:
# config/initializers/callback_terminator.rb
ActiveSupport.halt_callback_chains_on_return_false = false
So now for every callback you need to halt the transaction you need to throw(:abort)
explicitly:
class Person < ApplicationRecord
before_create do
throw(:abort) if you_need_to_halt
end
end
8 - Parameters does not inherit from Hash anymore
Rails 5 now logs some deprecation warnings for some Hash
related methods on ActionController::Parameters
. Check the PR
The warnings are like this:
=> (byebug) params.permit(:page, :per).reverse_merge(page: 1, per: 10)
# DEPRECATION WARNING: Method reverse_merge is deprecated
# and will be removed in Rails 5.1,
# as `ActionController::Parameters` no longer inherits from hash.
# Using this deprecated behavior exposes potential security problems.
# If you continue to use this method you may be creating a security vulnerability in your app that can be exploited.
# Instead, consider using one of these documented methods which are not deprecated:
# http://api.rubyonrails.org/v5.0.0.rc2/classes/ActionController/Parameters.html (called from index at (byebug):1)
{"page"=>"5", "per"=>"25"}
9 - Test http request methods
ActionController::TestCase
has changed, so on your controller tests or request tests, even if you use rspec-rails
. Check the PR
You may see warnings like this:
ActionController::TestCase HTTP request methods
will accept only keyword arguments in future Rails versions.
Examples:
get :show, params: { id: 1 }, session: { user_id: 1 }
process :update, method: :post, params: { id: 1 }
The idea here is to use keyword arguments over positional arguments. This is a simple code change.
So if you had this in you tests:
get :show, id: 1
You'll need to change to:
get :show, params: { id: 1 }
The keyword arguments accepted are: params
, session
, flash
, method
, body
and xhr
.
Conclusion
The Rails community has been hard at work improving the Rails framework over the last few years. In fact after almost 12 years Rails has shown to be an exceptionally productive and stable framework. This was a major upgrade and had only a few breaking changes. Great deprecation notices will make the upgrade completely painless.