Rails 3 user notes

06 Aug 2010 – Warsaw

The future is now

After some hacking, experimenting and micro-apps with Ruby 1.9 and Rails 3 betas I’ve decided to use this still-considered-bleeding-edge stack for a new project here at Aenima. There’s a lot of new stuff both on the surface and under the hood when switching from Ruby 1.8 + Rails 2.x, so I’ve obliged myself to take notes about new, suprising or otherwise worth mentioning (and memorizing) stuff. It’s not going to be a comprehensive tutorial, HOWTO or whatever-you-call it, but should have just enough information for competent Rails 2.x programmer who wants to give Rails 3 a try without nasty surprises.

Forget system Ruby, It’s the last call to install RVM

Trying to install Ruby 1.9 system-wide, especially on Debian-based systems (Ubuntu) and to live side-by-side with existing Ruby 1.8 is asking for trouble. If you do it, bad dark unicorns will step from oblivion and rip the guts out of your system with their horns.

So, RVM it is. It’s an awesome tool by Wayne E. Seguin, in case you lived under a stone for the last half year and haven’t tried it yet. As for the pitfalls, there’s only one for Ubuntu users: the piece warning about “no ‘&& return’ in .bashrc” is crucial because it’s basically about Ubuntu’s default .bashrc.

After installing rvm (and restarting terminal, making sure rvm is working etc.) all that’s left is

rvm install ruby-1.9.2-head
rvm use ruby 1.9.2-head
gem install rails --pre

I’m using Ruby 1.9.2-head here simply out of habit: I know there’s some rc out with stable on the horizon, but I’ve never had problems with the trunk version (since at least march) and it will give me all the “rc” and “stable” versions goodness on updating.

RVM, while solving most serious problems about developing a Rails 3 app under Ruby 1.9, introduces a few new issues (or pitfalls) on its own, so keep reading.

There’s no escape from Bundler

Bundler is the default and only way for Rails 3 to work with gems. It might be possible to force Rails 3 into working with gems without Bundler in the middle, but it’s a dumb (borderline brainfuck) idea and I’ve never considered it.

If you’ve never used Bundler before with some Rails 2.3 application, it’s better to learn this tool on the old stack that to make a full leap. Bundler introduces quite a shift in both philosophy and methodology (workflow), so it deserves some time dedicated just to learning its fundamentals. The good news is that it’s working like a charm now and I haven’t ran into single Bundler bug for a few months now (and thanks to Drogomir Strzałek I’m using Bundler on a daily basis since january).

So, port your existing Rails 2.3 app to use Bundler. Switching BitsPudlo to Bundler took me 30 minutes and I’m a pretty slow guy with new tools and with git branches there’s no risk involved.

I’ve been using older versions of Bundler (since 0.6 actually) and switching to 1.0 RC also required some learning: the commands and workflow changed a bit, mostly ones related to locking the gemset.

RVM + Bundler + Capistrano needs some love to work together

For starters, Capistrano should run bundle install during deploy:

namespace :deploy do
  desc "Run bundler command for installing gems"
  task :bundler, :roles => :app do
    run "cd #{current_path}; bundle install"
  end
end

after("deploy:update_code", "deploy:bundler")

Also, when there is RVM on the server, rvm use ruby-1.9.2-head should be ran on every shell login (otherwise someone can incidentally screw things). I prefer the former, as every application has its own shell account anyway so there’s no need for to use system ruby by default.

But that doesn’t solve all the Capistrano-RVM cooperation issues. RVM has a Capistrano plugin to make it work smoothly, so this should go into deployment recipe as well:

# taken from http://rvm.beginrescueend.com/integration/capistrano/
set :rvm_type, :user                      # we have RVM in home dir, not system-wide install
$:.unshift("#{ENV["HOME"]}/.rvm/lib")     # Add RVM's lib directory to the load path.
require "rvm/capistrano"                  # Load RVM's capistrano plugin.
set :rvm_ruby_string, 'ruby-1.9.2-head'   # Or whatever env you want it to run in.

I found myself in a situation when Bundler complained and threw an error while running bundle install during deploy. Putting this in deployment recipe fixed the problem

default_run_options[:pty] = true

Mongrel

gem install mongrel --pre

will install a version of (1.2 pre) Mongrel that compiles and works nicely with Ruby 1.9.2 and Rails 3.

Databases

For MySQL, mysql2 is the way to go — it’s Ruby 1.9 compatible and we might see some async performance improvements (thanks to Ilya) in that gem.

For PostgreSQL, last time I tried gem pg had some issues, but that was a long time ago.

Drogomir has been running Mongomapper with Ruby 1.9 and Rails 3 with lot of success, so MongoDB is also a viable choice.

A rule of thumb that applies to every gem, not only db-related ones: check it on IsItRuby1.9

Testing stack

All the sane testing tools have versions/forks that work with Ruby 1.9.2 and Rails 3 already. Because of this adding my favourite test stack only required googling which versions and/or forks should be chosen for compatibility.

So, to get a popular set of RSpec + Cucumber + Factory_girl + Capybara, here’s what should land in Gemfile:

gem 'rspec', '>= 2.0.0.beta.11'
gem 'rspec-rails', '>= 2.0.0.beta.11'
gem 'factory_girl'
gem 'factory_girl_rails'
gem 'capybara'
gem 'database_cleaner'
gem 'cucumber-rails', '>= 0.3.2'
gem 'cucumber', '>= 0.8'
gem 'launchy'    # So you can do Then show me the page

After usual bundle install, running

    rails generate rspec:install
    rails generate cucumber:install

will put all the required stuff to work.

Moar

…will be here after further adventures with Rails 3 on Ruby 1.9.2