Text

Upgrading to Rails 3 beta (part 1)

This post covers my experiences of upgrading a small Rails 2 application to boot with Rails 3.

Getting Started

First, we’ll need to install the Rails 3 beta.

As per the official instructions, we perform:

> [sudo] gem install tzinfo builder memcache-client
rack rack-test rack-mount erubis mail text-format
thor bundler i18n
> [sudo] gem install rails --pre

Before touching an existing app, it’s wise to commit any changes, and switch to a new branch. Using git, for example:

> git branch rails3
> git checkout rails3

The Rails Upgrade Plugin

rails_upgrade is a wonderful plugin that eases the transition to Rails 3. We can install it in an existing Rails 2 application with the following:

> script/plugin install git://github.com/rails/rails_upgrade.git

rails_upgrade adds a few handy rake tasks. Let’s start with:

> rails:upgrade:check

You’ll see a list of files that rails_upgrade has determined will need updating to work with Rails 3. Let’s stash our current version of these files using rails_upgrade:

> rails:upgrade:backup

We should commit now, as the next step will overwrite a bunch of our existing files.

Rerun Rails

Perhaps the simplest way to ensure an app will boot with Rails 3 is to rerun the Rails generator on it. We’ll do that now:

> rails .

The generator will prompt us before overwriting any files with Rails 3 versions. We’ll overwrite any files haven’t been modified since our app was first generated (e.g. config/boot.rb). For files that have been modified, we’ll take a backup (if rails_upgrade didn’t generate one already), and then tell Rails to overwrite. We’ll suffix our backup files with .rails2, following the rails_upgrade convention.

Merge the Backups

Now, we’ll take a good look at the backup files. Firstly, some might be of files that we don’t need or don’t use. For example, test/test_helper has changed, but I don’t use Test::Unit, so that change won’t affect me. I can safely delete the test_helper backup.

In other cases, the backups will need to be merged into their newly generated Rails 3 counterparts. For example, I needed to merge some custom application logic into app/controller/application_controller. We don’t need to merge config/routes, config/environment or config/environments/* just yet.

Regenerating routes

rails_upgrade can generate routes that conform to the new Rails 3 routing API from our old config/routes.rb. We can invoke the migration with:

> rails:upgrade:routes

Before running this rake task, ensure that config/routes.rb contains Rails 2 style routes. We’ll receive some output, such as:

SampleApp::Application.routes do
  resources :users do
      resources :posts
  end

  match '/' => 'site#index'
end

We can paste this into our config/routes.rb to start using the new Rails 3 routing API.

Generating a Gemfile

rails_upgrade can also generate a Gemfile to define our gem dependencies using bundler. In Rails 2, these dependencies were defined as config.gem statements in environment.rb. We can invoke the migration with:

> rails:upgrade:routes

Again, be sure that config/environment.rb contains Rails 2 code. We’ll receive output such as:

path "/path/to/rails", :glob => "{*/,}*.gemspec"
git "git://github.com/rails/rack.git"

gem "Rails", "3.0.pre"

gem 'authlogic'
gem 'cancan'
gem 'friendly_id'

In fact, the first few lines are no longer correct as we’re using Rails 3 beta (not the prerelease version). The above should read:

source 'http://gemcutter.org'

gem "rails", "3.0.0.beta"

gem 'authlogic'
gem 'cancan'
gem 'friendly_id'

We can go ahead and copy the latter into our app’s new Gemfile file.

Moving environment-specific gem dependencies

In Rails 2, each environment could add further gem dependencies. For example, a Rails 2 config/environments/test.rb file might contain the following:

config.gem 'webrat', :lib => false, :version => '>=0.7.0'
config.gem 'rspec',  :lib => false, :version => '>=1.2.9'

In Rails 3, environment-specific gem dependencies are also defined in the Gemfile. The above code becomes:

group :test do
  gem 'webrat', '0.7.0'
  gem 'rspec', '1.2.9'

end

There’s some fairly good documentation in the comments of the Gemfile generated by Rails 3. I recommend taking a couple of minutes to read it, and to check out the documentation for bundler.

Migrate environments

The final step is to ensure each of the files in config/environments now uses the new configure module method. The contents of each file should now be executed inside a configure block. Here’s an example config/environments/development.rb, specified in the new Rails 3 style:

SampleApp::Application.configure do
  config.cache_classes = false

  config.whiny_nils = true

  config.consider_all_requests_local       = true
  config.action_view.debug_rjs             = true
  config.action_controller.perform_caching = false

  config.action_mailer.raise_delivery_errors = false
end

Recall that gem dependencies should be moved to Gemfile, rather than be specified with a config.gem call.

Et viola!

And we’re done. The next step is to start the Rails server, and see which dependency breaks first. Note the new command:

> rails server

And the winner is… (for me at least):

authlogic-2.1.3/lib/authlogic/session/timeout.rb:26:in
'included': undefined method `before_persisting'
for Authlogic::Session::Base:Class (NoMethodError)

Fixing Authlogic, and the other gems I’m using will be covered in part 2.

Notes:

  1. louismrose posted this