I have created a few rails 3 sites, but i have never before ported an existing rails2 application to rails3. I will describe the problems i encountered. First off there were some very good resources (step-by-step descriptions) to guide me through it:
ActiveSupport::Callbacks
Before we wrote: [ruby] module Workflow class Base define_callbacks :before_something, :after_something def some_method run_callbacks :before_something puts "some method" run_callbacks :after_something end end class SpecificWorkflow < Base before_something :do_something def do_something puts "something" end end [/ruby] Now, this has changed. Into the following: [ruby] module Workflow class Base define_callbacks :something def some_method run_callbacks :something do puts "some method" end end end class SpecificWorkflow < Base set_callback :something, :before, :do_something def do_something puts "something" end end [/ruby] Which is pretty nice. It has the disadvantage we can only use :before and :after
callbacks anymore, but that was easily solved.
ActionController::ParamsParser
We hooked into the Rack middleware before the ActionController::ParamsParser
to make sure we return Bad Request when the parsing fails. This middleware has been renamed to ActionDispatch::ParamsParser
. Easy fix :)
safe_helper
removed?We prepared our Rails 2 project a long time ago, and used the rails_xss plugin. We used the safe_helper
all over our helper-methods, but apparently this is not supported in Rails 3. Bummer. So, before [ruby] def some_helper "<strong>something</strong>" end safe_helper :some_helper [/ruby] After: [ruby] def some_helper "<strong>something</strong>".html_safe end [/ruby] A bit annoying to do, a bit unfortunate, because we thought we were preparing ourselves for a smoother upgrade. Not entirely so.
Only after those steps did my rails get far enough to discover my routes. I did not change anything about the routes, just placed inside the correct block. I deleted my index.html
and put back my original application.html.haml
and the first view was working.
to_key
The to_key
was missing inside the user_session
model. I described that solution already in this blogpost. So i just needed to fix that.
ActionController::RecordIdentifier.singular_class_name
We used ActionController::RecordIdentifier.singular_class_name
, in rails3 this is replaced by ActionController::RecordIdentifier.dom_class
.
A feature we used a lot was I18n.t('.filter')
and this would look for operators.filter.filter
because the line was inside a partial _shared/_filter.html.haml
and called from the operators/index.html.haml
. Now this does not work anymore, and now instead I18n looks for _shared.filter.filter
. I did not find an easy way to solve this, just moved some translations. Luckily we did not override the translations of a partial based on the context where it was rendered yet. Does anybody has any tips on that?
In rails3 unobtrusive is the way to go. So, a remote_form_for
like [ruby] - form_remote_tag :url => update_url do [/ruby] becomes [ruby] - form_tag :url => update_url, :remote => true do [/ruby] Which seems easy enough. It does get more complicated when the :update
tag is used. For example: [ruby] - remote_form_for post, :update => {:success => "result_#{id}"} do |form| [/ruby] becomes [ruby] - remote_form_for post, :remote => true, :html => {:class => 'remote-post-form', :'data-update' => "#result_#{id}"} do |form| [/ruby] The :update
is no longer supported as before, and we have to perform some glueing ourselves. So i replaced the :update
by data-update
. And then inside javascript (e.g. application.js
) we can do the following: [javascript] jQuery(function($) { $(".remote-post-form") .bind("ajax:success", function(data, status, xhr) { var update_selector = $(this).attr('data-update'); $(update_selector).html(status); }); }); [/javascript] If you need more elaborate example, check this question on stackoverflow.
This has been replaced by _helpers
.
The active_layout
method, of a controller, no longer exists inside rails3. To replace it you need to use two methods:
action_has_layout?
returns true if a layout exists._layout
. This can be done, as known, by doing controller.send(:_layout)
.I had to upgrade Rspec 1 to v2. First off in the Gemfile i added the correct version. I removed the rspec.rake
file. I ran [ruby] rails g rspec:install [/ruby] But still all rake spec
commands were missing. The fix was simple. In the Gemfile
make sure the rspec-rails
is also usable from development mode: [ruby] group :development, :test do gem 'rspec-rails' end [/ruby] Now on to fixing the tests!
In the upgrade from rspec1 to rspec2 a lot of things have changed. What i encountered:
Spec::
by RSpec::
controller_name 'users'
no longer exists, write a surrounding describe UsersController do
instead (that is also clearer imho)Before, in rspec1, ControllerExampleGroup
was a class and you could add code to it. So for instance, we had a file like this in our support folder: [ruby] module RSpec module Rails module Example class ControllerExampleGroup let(:the_account ) { Factory(:account) } let(:the_user ) { Factory(:user)} end end end end [/ruby] A bit larger, but you get the picture: this allowed us to define a set of shared let
definitions. In rspec-2 this is no longer possible this way, because ControllerExampleGroup
is now a module. I handled that like this: [ruby] module Lets def self.included(base) base.let(:the_account ) { Factory(:account) } base.let(:the_user ) { Factory(:user)} end end [/ruby] and inside my spec_helper
this file is automatically required (since it is stored in the support folder) and i just add [ruby] config.include(Lets) [/ruby]
config.extend
I also noticed that using config.extend(ModuleName)
dit not work anymore. Instead i had to write (on the same place, inside the configure block) : [ruby] Rspec.configure do |config| .. include ModuleName .. end [/ruby] and that worked for me.
Do you have more hints to share? What bumps did you find and how did you overcome them?
Comments
I just tried a similar upgrade and have 2 problems, one of which I 'fixed' and one still outstanding. 1. Kept getting error "uninitialized constant Authlogic' which I fixed by adding a require 'authlogic' in application.rb. I am not convinced that this is correct, but it did get things to work after everything else I tried failed (including viewing your referenced posts). 2. I am now getting the following error immediately after entering an id/password and clicking the submit button from my login page. Seems to me it's a routes problem but I can't figure it out: Unknown action The action '#' could not be found for UserSessionsController Any comments/suggestions appreciated and maybe #1 will help someone else.
Hi Jon, if you are using a non-standard gem-line in your Gemfile, it could help to add an explicit require there. E.g. something like <code>gem "authlogic-rails3", :git => '...', :require => 'authlogic'</code>. Not sure if that is the case. I did need to add more explicit requires, while i also needed to add the <code>lib</code> path to the load-path explicitly. Your second problem looks like a routing problem indeed :)
I tried putting the 'require' in the Gemfile, but that didn't work... dunno why not. I was finally able to work around the uninitialized constant problem by just putting require 'authlogic' in my application.rb file, right under the require 'rails/all' expression.
Add comment