I used to be a strong adherent to tracking edge rails. Up until the release of rails 2.3 I let most of my frequently updated projects track edge with a vendored copy of rails, and it rarely caused me any trouble. When 2.3 hit I rethought all that.

With Rails 3 development ramping up I suspected there’d be significant disruption taking place; even with comprehensive test suits I didn’t want the headaches of keeping track of that, and I didn’t want to spoil the pleasant surprises I expected when Rails 3 landed.

A year on from the Rails 3 announcement, with that release seemingly approaching, and with a few plugins to keep up to date, it seemed like this Christmas break was the time to start work on porting at least one relatively complex app over and see what it took. So I picked Catapult Magazine (a relatively stable codebase, no impending releases, uses my fork of theme_support) and got to work.

[Please don’t take any of this as authoritative. I’ve not been keeping up with rails-core lately and I’m posting these notes in case they’re useful to someone. Hopefully when Rails 3 is actually released there’ll be clearer and more definitive explanations of the changes.]

I cloned the current rails HEAD into vendor/rails and for good measure used the rails command to create myself a skeleton application elsewhere that I could use for reference. I then called the tried and tested rake rails:update, hoped for the best, and hit my first stumbling block.

The structure of the rails initializers has changed significantly and the usual rake call won’t work. Instead I had to pull config/boot.rb across from my sample app and do a little restructuring of my startup files:

  1. As has been well covered, rails 3 will use the new Gem Bundler and I created a Gemfile in my app’s root folder listing out my gem dependencies, then called ’ gem bundle’ to pull them all down

  2. Everything is built on rack these days so we need a config.ru file in the root of our rails folder. Mine contains:

      # Require your environment file to bootstrap Rails
      require ::File.expand_path('../config/environment',  __FILE__)
    
      # Dispatch the request
      run Catapult::Application.instance
    
  3. Most of what we would have had in config/environment.rb now lives in config/application.rb. Mine looks like:

      require File.expand_path('../boot', __FILE__)
      module Catapult
        class Application < Rails::Application
          config.time_zone = 'UTC'
    
          config.generators do |g|
            g.orm             :active_record
            g.template_engine :erb
            g.test_framework  :rspec
          end
        end
      end
    
      # For clearance
      DO_NOT_REPLY = "donotreply@catapultmagazine.com"
    
  4. With all of that moved, config/environment.rb is now quite minimal:

      # Load the rails application
      require File.expand_path('../application', __FILE__)
    
      # Initialize the rails application
      Catapult::Application.initialize!
    
  5. Each of the files in config/environments needs to be wrapped in a block:

      Catapult::Application.configure do
        # previous contents of file
      end
    
  6. The Rakefile now looks like:

        require File.expand_path('../config/application', __FILE__)
    
        require 'rake'
        require 'rake/testtask'
        require 'rake/rdoctask'
    
        Catapult::Application.load_tasks
    
  7. I also had to install the i18n gem and moved all my plugins out of the way so I can reintroduce them one-by-one.

  8. Changes to config/routes.rb aren’t essential but I reworked mine following the examples from Yehuda’s blog entry

  9. In Rails 3 RAILS_ROOT has been deprecated in favour of Rails.root and my app relied quite a bit on the former. A quick search & replace sorted that out.

So with all of those changes complete I was able to run rake rails:update to pick up the updated scripts, etc. and a call to script/server launched the app. Kinda. What followed was a long process of confusing errors, almost all of which could be traced back to plugin-related code that needed to be commented out. But once that was taken care of the skeletal remains ran cleanly.

The next step will be trying to get the plugins back in and running cleanly. I’ll try and blog my progress on that as it unfolds.