Upgrade Rails from 2.3 to 3.0

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.

  1. Preparations
  2. Ruby version
  3. Tools
  4. XSS protection
  5. Config files
  6. Gems
  7. RSpec
  8. Ignoring Rails modules
  9. Escaped HTML by default
  10. Deprecations
  11. 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 of named_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 use save(: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 of model.errors[]

  • There is a new syntax for presence validations:

# Before:
validates_presence_of :email

# Now:
validates :email, presence: true
  • ActiveRecord::Base.colorize_logging and config.active_record.colorize_logging are deprecated in favor of Rails::LogSubscriber.colorize_logging or config.colorize_logging.

Action Mailer

  • :charset, :content_type, :mime_version, :implicit_parts_order are all deprecated in favor of ActionMailer.default :key => value style declarations.
  • Mailer dynamic create_method_name and deliver_method_name are deprecated, just call method_name which now returns a Mail::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 the format.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 of Rails.root
  • RAILS_ENV in favor of Rails.env
  • RAILS_DEFAULT_LOGGER in favor of Rails.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.

Get the book