Upgrade Rails from 2.3 to 3.0
This article is the first of our Upgrade Rails series . We will be covering the most important aspects that you need to know to update your Ruby on Rails application from version 2.3 to 3.0 .
- Preparations
- Ruby version
- Tools
- XSS protection
- Config files
- Gems
- RSpec
- Ignoring Rails modules
- Escaped HTML by default
- Deprecations
- 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 3.0 requires Ruby 1.8.7 or higher, but no more than 1.9.3 . If you want to use Ruby 1.9.x, we recommend you skip directly to 1.9.3. Also Ruby 1.9.1 is not usable because it has segmentation faults on Rails 3.0. That means that the compatible Ruby versions for Rails 3.0 are 1.8.7, 1.9.2 , or 1.9.3.
3. Tools
There is an official plugin that helps the upgrade process. You just need to install the script by doing script/plugin install git://github.com/rails/rails_upgrade.git
and then run rake rails:upgrade:check
to see most of the files you need to upgrade in your application. It also provides some other generators to upgrade specific areas in your app, like routes or gems.
Sometimes it’s also useful to check which files changed between two specific versions of Rails. Fortunately Rails Diff makes that easy.
4. XSS protection
In this version, Rails automatically adds XSS protection in order to escape any content, so you will probably need to update your templates according to this. Luckily there is an official plugin for this. We recommend you take a look at this.
5. Config files
Rails 3 introduces the concept of an Application object. An application object holds all the specific application configurations and it’s similar to the current config/environment.rb from Rails 2.3. The application object is defined in config/application.rb. You should move there most of the configuration that you had in config/environment.rb.
In terms of routes, there are a couple of changes that you need to apply to your routes.rb file. For example:
# Rails 2.3 way:
ActionController::Routing::Routes.draw do |map|
map.resources :products
end
# Rails 3.0 way:
AppName::Application.routes do
resources :products
end
If you installed the plugin mentioned in step 3, you can run ‘rake rails:upgrade:routes” to generate a new set of routes. You can go to this article to read an in-depth article about this topic.
6. Gems
Bundler is the default way to manage Gem dependencies in Rails 3 applications. You will need to add a Gemfile in the root of your app, define all your gems there, and then get rid of the config.gem statements.
# Before:
config.gem 'aws-sdk', :version => '1.0.0' # (config/environment.rb)
config.gem 'pry', :version => ['>= 0.6.0', '< 0.7.0'] # (config/development.rb)
# Now:
(Gemfile)
gem 'aws-sdk', '1.0.0'
group :development do
gem 'pry', '~> 0.6.0'
end
Remember that if you installed the plugin mentioned in step 3, you can run rake rails:upgrade:gems
. This task will extract your config.gem calls and generate code that you can put in your Gemfile.
7. RSpec
If you are using RSpec 1.x for your tests, you should update to RSpec 2.x. You may need to update some references to Spec
with RSpec
.
8. Ignoring Rails Modules
If you don’t need to load a module (let’s use actionmailer as an example), in Rails 2 you would use a configuration like this in your environments.rb file:
config.frameworks -= [ :action_mailer ]
For Rails 3 you need to remove that and change how you require rails
in your new application.rb file:
require "rails"
# instead of `require "rails/all"`
%w(
active_record
action_controller
active_resource
rails/test_unit
).each do |framework|
begin
require "#{framework}/railtie"
rescue LoadError
end
end
9. Escaped HTML by default
In Rails 3 you no longer need to use the h
helper method to escape HTML. It is now escaped by default. If you need to tell Rails to not escape the HTML you will need to call .html_safe
on that string.
10. Deprecations
There are a bunch of deprecations that happen during this version:
Active Record
-
The method to define a named scope is now called
scope
instead ofnamed_scope
. -
In scope methods, you no longer pass the conditions as a hash:
# Before:
named_scope :active, :conditions => ["active = ?", true]
# Now:
scope :active, where("active = ?", true)
-
save(false)
is deprecated, so you should usesave(:validate => false)
. -
I18n error messages for Active Record should be changed from
:en.activerecord.errors.template
to:en.errors.template
. -
model.errors.on
is deprecated in favor ofmodel.errors[]
-
There is a new syntax for presence validations:
# Before:
validates_presence_of :email
# Now:
validates :email, presence: true
ActiveRecord::Base.colorize_logging
andconfig.active_record.colorize_logging
are deprecated in favor ofRails::LogSubscriber.colorize_logging
orconfig.colorize_logging
.
Action Mailer
:charset
,:content_type
,:mime_version
,:implicit_parts_order
are all deprecated in favor ofActionMailer.default :key => value
style declarations.- Mailer dynamic
create_method_name
anddeliver_method_name
are deprecated, just callmethod_name
which now returns aMail::Message
object.
# Before:
message = UserMailer.create_welcome_email(user)
UserMailer.deliver(message)
# or
UserMailer.deliver_welcome_email(user)
# Now:
UserMailer.welcome_email(user).deliver
template_root
is deprecated, pass options to a render call inside a proc from theformat.mime_type
method inside the mail generation block.- The body method to define instance variables is deprecated (
body {:ivar => value}
), just declare instance variables in the method directly and they will be available in the view.
# Before:
def welcome_email(user)
...
body {:user => user, :url => "https://fastruby.io"}
end
# Now:
def welcome_email(user)
...
@user = user
@url = "https://fastruby.io"
end
- Mailers should now be in app/mailers instead of app/models.
ERB Syntax
Block helpers that use concat (e.g., form_for, form_tag) will need to replace <%
with <%=
. The current syntax will continue to work for now, but you will get deprecation warnings since it will go away in the future.
AJAX Helpers
AJAX JavaScript helpers have moved to be unobtrusive and use :remote => true
. Depending on the helper call, some JavaScript event listeners may need to be added. For example:
link_to_remote ("Update Example",
:update => 'result_div_id',
:url => {:action => 'example'})
Will need to change to:
link_to "Update Example", { :action => 'example' }, :remote => true, :id => 'my_link'
And a JavaScript event listener will need to be added for what “update” is doing.
Example:
$("#my_link").on('ajax:success', function(response, status) {
$("#result_div_id").html(response.responseText)
})
Metal
Since Rails 3 is closer to Rack , the Metal abstraction is no longer needed.
This is the official explanation of what you need to do to update your existing Metals:
- If your metal behaves like a middleware, add it to the middleware stack via config.middleware.use. You can use methods on the middleware stack to control exactly where it should go.
- If it behaves like a Rack endpoint, you can link to it in the router. This will result in more optimal routing time, and allows you to remove code in your endpoint that matches specific URLs in favor of the more powerful handling in the router itself.
For the future, you can use ActionController::Metal to get a very fast controller with the ability to opt-in to specific controller features without paying the penalty of the full controller stack.
Railties
Railties deprecates the following constants during this version:
RAILS_ROOT
in favor ofRails.root
RAILS_ENV
in favor ofRails.env
RAILS_DEFAULT_LOGGER
in favor ofRails.logger
Also, PLUGIN/rails/tasks
and PLUGIN/tasks
are no longer loaded all tasks, now must be in lib/tasks
.
# Before:
vendor/plugins/ombulabs_patches/tasks/s3_backup.rake
# Now:
lib/tasks/ombulabs_patches/s3_backup.rake
11. Next steps
After you get your application properly running in Rails 3.0, you will probably want to keep working on this Rails upgrade journey. So don’t forget to check our complete Rails upgrade series to make that easy.
If you’re not on Rails 3.0 yet, we can help! Download our free eBook: The Complete Guide to Upgrade Rails .