Wednesday, February 3, 2010

notes from yet another rails 3 upgrade

These tips and tricks are valid as of today, February 3rd, 2010. Who knows what next week will bring, but for now, I thought compiling some of the techniques and hacks I've seen might help others.

Rails Related

If you see a "no such file to require: rails/all" you probably don't have Rails installed correctly. I was basing my upgrade on the great screencast produced by Topfunky over at peepcode.com, and his method didn't work for me. To get things running I added this to my Gemfile:

path "/Users/jack/git/rails", :glob => "{*/,}*.gemspec"
gem "rails", "3.0.pre"
gem "rails", "3.0.0.beta" # Just changed today it seems


Obviously, change the path to wherever you have rails checked out locally.

HAML

If you see something like this: Missing template articles/index with {:formats=>[:html]} in view path

you probably need to install haml.


$ haml --rails .


and then you'll likely see an error about html_safe!

Geoff has a nice little idea going with a config/initializers/rails3_hacks.rb file which I've also done. You can drop this in and get by the errors for now:

projects/app master > cat config/initializers/rails3_hacks.rb
class String
def html_safe!() self end
def html_safe?() true end
def safe_concat(value) value+self end
end


WillPaginate

Looks like Mislav and other's have been doing a lot of work in upgrading the plugin. If you see a "no paginate method for Class...." error, try cloning the source down locally, check out the rails 3 branch,build and install that gem and then update your Gemfile:

...
gem 'will_paginate', '3.0.pre'
...

It also seemed that WillPaginate wasn't being required into my app. For now I've created a config/initializers/requires.rb file and dropped in random requires for attention later. Putting a "require 'will_paginate'" in there fixed that up nicely.

Update:
Seems something's broken now. I'm getting this error:

uninitialized constant ActiveRecord::Calculations::CALCULATIONS_OPTIONS

Seems WP relies on that constant without checking for its existence, and it looks like its gone now. Easy enough to quick patch it if you need to get by it, but I imagine it'll be fixed in the rails3 branch soon enough.
Assorted Issues

HTMLEntities doesn't seem to be working, so I commented that out for now. For a great beginning list of what gems should be working, take a look here: http://wiki.rubyonrails.org/rails/version3/plugins_and_gems

Devise: not ready for rails 3 yet. I think they're trying to see what routing changes will settle and how that will affect their code. I'm going to see if I can pop over into that and help out a bit as I'd love to keep using it in this app.

new_rails_defaults.rb: I had an error from this file and realized it's old anyway, so git rm and it's gone.

Passenger

I also overhauled a bunch of other ruby related items on my boxes recently, and one of those items was passenger. After updating to 2.2.9, reinstalling the module, changing RailsEnv to RackEnv, things are mostly good. Remember to point to the right ruby if you're using rvm. I also deleted the config.ru file per their recommendation: "Smart spawning (the mechanism with which REE’s 33% memory reduction is implemented) is *not* supported for Rack apps. This means that if you want to utilize smart spawning with Rails 3, then you should remove your config.ru file."

I think that's it for now. I imagine I'll update this page as I deal with new issues. Pretty excited about the new changes and starting to actually make use of them.

Update

Previous notes were from my macbook pro. Now that I'm back on the iMac I'm finding other issues. Latest is:

/Users/jack/git/rails/activesupport/lib/active_support/dependencies.rb:167:in `require': no such file to load -- rails/commands/rails (LoadError)

I'm actually not sure if that was something I did as it looks like its definitely just "require 'rails/commands'" in the latest source, but either way, if you're seeing that, just take off the second rails in that line. Correct line should be:

require 'rails/commands'

at the end of your script/rails.

Bundler

Somehow just found myself facing this:

projects/app master > bundle install
/Users/jack/.rvm/gems/ree-1.8.7-2010.01/bin/bundle: line 1: require: command not found

A quick cat and I see something's changed, no #!...ruby line to see. Realized I had bundler 0.9.0 and 0.9.0.pre4, so I uninstalled them both, and reinstalled with:

$ gem install bundler --pre

and now have bundler-0.9.0.pre5 installed.

Still things are borked, but it seems its a result of github being down: "Page did not respond in a timely fashion."

Will try again in a few to make sure this gets me back on track.

Update

Ok, github's back, and just saw a tweet from Wycats. Looks like 0.9.0 final is out now, but it's recommended to wait til tomorrow and 0.9.1 + some docs. YMMV.

Application != ApplicationController

So, the app I'm converting was originally written in Merb, was partially converted to Rails 2, and is now on its way towards Rails 3. In this transition I've generally remembered what pieces to change from Merb to Rails, but I had a nice stumble earlier in forgetting to change a controller. So, if you find yourself in a place where you have a route that you know works, but is not recognized, make sure your controller is named whatever_controller.rb, and contains the code:

class WhateverController < ApplicationController
...
end

not "< Application". You'll an error about a route missing and could easily spend a couple hours missing the obvious.

Routes

I keep tripping myself up with this. Lets say you have a route defined as:


match 'foobar/:foobar' => 'foobar#foobar', :as => :foobar


These calls will all fail:


ree-1.8.7-2009.10 > app.foobar_path
ActionController::RoutingError: No route matches {:action=>"foobar", :controller=>"foobar"}
... from (irb):3
ree-1.8.7-2009.10 > app.foobar_path('')
ActionController::RoutingError: No route matches {:use_defaults=>false, :action=>"foobar", :foobar=>"", :controller=>"foobar"}
... from (irb):4
ree-1.8.7-2009.10 > app.foobar_path('test')
=> "/foobar/test"


until that last one which passes in a value. This makes sense, as the route defines foobar as a requirement, and not passing in a value is an 'error'. It's a little less obvious that an empty string doesn't satisfy it to me, and definitely not obvious when you have this in a loop and an object just happens to be missing its value for foobar.

One way around this is to make the :foobar piece optional, and handle that reality in your controller elsewhere. You could also protect against this by checking that object.foobar exists in your loop, and not linking unless it does.

I've also just realized that for a certain route of mine, one that passes in domain names, sending in 'euraeka.com' will result in an error. I'm not sure if this is the recommended solution, but its letting me progress for now:


match 'domain/:domain' => 'search#domain', :as => :domain, :domain => /.+/


I'm using domain here instead of host as I think host might be reserved somewhere. Couldn't seem to get it to work before, so if you're having that issue, let me know.