Thursday, March 18, 2010

Getting Rails 3.0 running with “My Stack” on Ruby 1.9.1

I’m pretty excited about Rails 3.0. It really feels like a polished version of the framework, much like Snow Leopard was for Leopard OS X.

At this stage in the game I really don’t want to be starting any new projects with Rails 2.3.5, so I thought I would see if it was possible to get Rails 3.0-beta running with “My Stack”—a set of gems/plugins used on all of my projects. Admittedly, there are probably some others that I should be using, but these are definitely the essentials:

  • haml (with sass)
  • compass
  • authlogic
  • shoulda
  • factory_girl
  • will_paginate

Just to keep things interesting I thought I would throw Ruby 1.9.1 in there to mix things up.

First, stop was to check out A registry setup by Engine Yard to track which plugins are Rail 3, Thread Safe, JRuby, and Ruby 1.9 compatible. Let’s see how my stack faired (note, I’m only interested in Rails 3 and Ruby 1.9):

OK, let’s look at each plugin, step by step:

Haml (Confirmed to work)

Installing Haml was pretty straight forward:

# Gemfile
gem "haml", "2.2.21" 

# command line (rails root of course)
bundle install
haml --rails . 

Compass (Confirmed to work)

Install Compass was also straight forward:

# Gemfile
gem "compass", "0.10.0.pre9" 

# command line
compass --rails -f blueprint . --css-dir=public/stylesheets/compiled --sass-dir=app/stylesheets

Authlogic (Unknown to work)

While Authologic is officially “not working”, reports from end users suggest it is. Following along with Ryan Bates screencast, you just need to translate the script/generate commands to rails generate and also check for new options. To setup Authlogic with your application, add it to your Gemfile.

# Gemfile
gem "authlogic", :git => "git://" 

Shoulda (Unknown to work)

There are no reports regarding shoulda (as there is no version number assigned to, and you can't comment without a version number). Although there is a rails3 branch, it hasn’t been touched since mid-January. Well let’s give it a go and see how far we get:

# Gemfile
gem "shoulda", :git => "git://", :branch => "rails3", :group => :test

A couple of options to note. :branch specifies the branch of the git repo, and :group the environment. You won’t be needing shoulda in production.

So how did we get on? Trying rake test... Boom!

DEPRECATION WARNING: RAILS_ROOT is deprecated! Use Rails.root instead. (called from join at ~/.bundle/ruby/1.9.1/bundler/gems/shoulda-b78dbf514bbce3272023d3a4742474857c2eb3c3-rails3/lib/shoulda/autoload_macros.rb:40)
  ~/.bundle/ruby/1.9.1/bundler/gems/shoulda-b78dbf514bbce3272023d3a4742474857c2eb3c3-rails3/lib/shoulda/autoload_macros.rb:40:in `join': can't convert #<Class:0x1297f3c> into String (TypeError)  

OK, let’s remove shoulda gem from:

rm -rf ~/.bundle/ruby/1.9.1/bundler/gems/

And let’s try a more up to date fork. This looks like it:

# Gemfile
gem "shoulda", :git => "git://", :branch => "rails3", :group => :test

You get this message but it doesn’t appear to be anything to worry about (I hope):

shoulda at ~/.bundle/ruby/1.9.1/bundler/gems/shoulda-87e75311f83548760114cd4188afa4f83fecdc22-rails3 did not have a valid gemspec.
  This prevents bundler from installing bins or native extensions, but that may not affect its functionality.
  The validation message from Rubygems was:
    ["test/rails_root/db/development.sqlite3", "test/rails_root/doc", "test/rails_root/log/development.log", "test/rails_root/log/production.log", "test/rails_root/log/server.log", "test/rails_root/log/test.log", "test/rails_root/test/fixtures", "test/rails_root/test/functional", "test/rails_root/test/integration", "test/rails_root/test/unit"] are not files

And running rake test works. Let’s convert a controller over.

context "create card" do
    setup { post :create, :card => cards(:one).attributes }

    should_change "Card.count", :by => 1
    should_redirect_to("new card") { card_path(assigns(:card)) }

Almost works, but dies on the should_change marco.

1) Error:
test: create card should change Card.count by 1. (CardsControllerTest):
NoMethodError: undefined method `call' for #<Arel::Value:0x172eba8>
      ~/.bundle/ruby/1.9.1/bundler/gems/shoulda-87e75311f83548760114cd4188afa4f83fecdc22-rails3/lib/shoulda/macros.rb:45:in `block in should_change'
      ~/.bundle/ruby/1.9.1/bundler/gems/shoulda-87e75311f83548760114cd4188afa4f83fecdc22-rails3/lib/shoulda/context.rb:360:in `call'
      ~/.bundle/ruby/1.9.1/bundler/gems/shoulda-87e75311f83548760114cd4188afa4f83fecdc22-rails3/lib/shoulda/context.rb:360:in `block in create_test_from_should_hash'  

Looks like a change in ActiveRecord is causing a few problem there.

Conlusion on Shoulda: OK, it might be the only macro failing, but I think at this stage i will leave shoulda at this point. I’ve filed an issue and if I have some time I will look into it myself.

Factory Girl (Unknown to work)

While the owner says it’s “not working”. A commentator says it does. Let’s give it a go:

# Gemfile
gem 'factory_girl', :git => 'git://', :branch => 'rails3', :group => :test

# command line
bundle install

And convert a controller over to use factories instead of fixtures (yuk!).

# factories.rb

Factory.define :card do |c| 'Lorem ipsum dolor sit amet'

# cards_controller_test.rb
require 'test_helper'

class CardsControllerTest < ActionController::TestCase

  setup do
    @card = Factory(:card)    

  test "should get index" do
    get :index
    assert_response :success
    assert_not_nil assigns(:cards)

  test "should get new" do
    get :new
    assert_response :success

  test "should create card" do
    assert_difference('Card.count') do
      post :create, :card => @card.attributes

    assert_redirected_to card_path(assigns(:card))

  test "should show card" do
    get :show, :id => @card.to_param
    assert_response :success

  test "should get edit" do
    get :edit, :id => @card.to_param
    assert_response :success

  test "should update card" do
    put :update, :id => @card.to_param, :card => @card.attributes
    assert_redirected_to card_path(assigns(:card))

  test "should destroy card" do
    assert_difference('Card.count', -1) do
      delete :destroy, :id => @card.to_param

    assert_redirected_to cards_path

Yes, it’s a very simple example of using a factory. So there might be some bugs lurking around. But I’m guess it’s safe to say this is usable.

Will Paginate (Confirmed to work)

This looks promising.

# Gemfile
gem "will_paginate", "3.0.pre"  

# command line
bundle install

Again, it’s a simple example, but I think it’s safe to say we’re good to go.

# cards_controller.rb
@cards = Card.paginate :page => params[:page], :per_page => 1

# index.html.haml
= will_paginate @cards


Well it is marked Beta for a reason—and that’s for the gem/plugin ecosystem to catch up. With my limited playing with Rails 3-beta I would be confident writing applications with it, and while most plugins seem to be compatible, I feel a little uneasy doing production projects until there is a broader range of plugins compatible with it. Looks like I will be staying with Rails 2.3.5 a little longer.

Please note this blog is no longer maintained. Please visit CivilCode Inc - Custom Software Development.