Gotchas When Upgrading to Rails 2.1
Posted by Chad Pytel
Jun 19
We’ve upgraded several Rails 2.0 application to Rails 2.1 now, and we’ve compiled a list of little things to keep in mind as you upgrade. Hopefully this list will help you avoid banging your head against a wall.
Partial Updates
The updated_at and updated_on columns are NOT automatically updated on a #save on an AR object in Rails 2.1, unless another column has also changed. In each of the cases where we were relying on this behavior, we were using it to detect in a general way that something had changed with the model (without introducing a dependency on acts_as_modified). Because Rails 2.1 has dirty attribute checking, these methods were able to be refactored using this new functionality.
Will Paginate
Older versions of will_paginate are broken on 2.1 (stack level too deep errors), to resolve, install the latest version of will_paginate like this:
sudo gem install mislav-will_paginate -s http://gems.github.com
Then put require ‘will_paginate’ in an initializer or in environment.rb (you need to have added vendor/gems to load path already to do that).
This newer will_paginate has changed the #page_count method to be #total_pages instead, so you’ll have to keep that in mind. Which means, some of the will_paginate view helpers changed as well – if you’ve monkey patched them (you haven’t unless you’re me!) look for changes there too!
Finally, Squirrel’s WillPagination module provides a #page_count method. To get a #total_pages from squirrel results, we temporarily monkey patched Squirrel by adding a lib/extensions/squirrel.rb which was just…
1 2 3 4 5 |
module Squirrel module WillPagination alias_method :total_pages, :page_count end end |
We’ll need to update Squirrel soon to have this built in so that its compatible with the latest version of will_paginate.
Shoulda
Make sure you’ve upgraded Shoulda if you get errors about not being able to find fixture methods and/or assert, especially if these errors appear in setup blocks.
HAML
Unfortunately, haml isn’t Rails 2.1 compatible. To fix this, upgrade to haml-2.0.
Reply-to in mailers
If you have the following hack in your mailer, just remove it. Rails 2.1 does it for you:
1 2 3 |
def reply_to(str) @headers["Reply-To"] = str end |
Changes in Active Record Attribute Filtering
ActiveRecord::Base#attributes does not allow filtering anymore (it does not accept :only, for example). You must do the filtering manually, with something like this:
1 2 3 4 |
def json_attributes_for(model, *attrs) attrs = [attrs].flatten.map(&:to_s) model.attributes.delete_if{|k,v| !attrs.include?(k) }.to_json end |
json_attributes_for(page, :id, :keyword) |
Changes in Template Rendering
Now in Rails 2.1, if you both foo.rhtml and foo.rxml exist and you aren’t explicitly specifying one or the other, Rails will render with foo.rxml. Renaming foo.rhtml to foo.html.erb fixes this, but in Rails 2.0, this was ok.
Relationship Optimized Eager Loading
In order to deal with the 1+n query problem, Active Record has changed how it does eager loading. Now, it will optimize out :includes on finders when they are not being used. “When they are not being used” is the key here. Active Record is supposed to noticed when there are additional conditions on the find that rely on the included table, and not leave it out.
However, on an association like this:
1 |
has_many :active_sites, :through => :clients, :source => :sites, :include => :domains, :conditions => 'domains.id IS NOT NULL' |
Active Record leave out the domains table, even though it shouldn’t. We fixed this by changing active_sites to just a normal method, as the bug doesn’t seem to happen in find, like this:
1 2 3 |
def active_sites sites.find :all, :include => [:domains], :conditions => 'domains.id IS NOT NULL' end |
has_finder
has_finder has been integrated into Rails 2.1 as named_scope, so you don’t need it anymore. However, you also shouldn’t keep it around. For example, has_finder-1.0.5 was giving us stack trace too deep exceptions when traversing a has_many :though association. Removing it in favor of named_scope fixed that issue.
In Conclusion
Those are the things that we’ve found that we feel might be helpful to other people out there. For the most part, upgrading to Rails 2.1 is a a straightforward process, and we’re quickly upgrading most of our apps.
Have you upgraded to 2.1 and run into anything that other people might hit? If so, feel free to add your gotchas to the comments.
Comments on this post
Jun 19
bryanl said,
Has the -a gems.github.com thing been resolved yet? I’m wary until I hear an OK from them. Check out the notice here: http://gems.github.com/
Jun 19
Chad Pytel said,
@bryanl, good call. I’ve updated the article to change it to the manual source specification. Thanks.
Jun 19
Josh Nichols said,
If you used the gem support from 2.1, you wouldn’t have to deal with an initializer for will_paginate.
This lets you do something like:
Jun 19
Louis-Mathieu Houle said,
I received some errors about number of arguments (3 for 2) when using time_select in DateHelper. It seems the API has changed, but not the doc
Jun 20
Daniel Insley said,
Markaby doesn’t work after the upgrade either, due to the changes in the way the template handling works. I’ve updated the latest Markaby trunk to support the changes. You can clone it from http://github.com/dinsley/markaby/tree/master if anyone is in need of it.
Jun 20
Chad Pytel said,
@josh: Thats a good point. We haven’t started using the new gem support yet in the apps we’ve upgraded, but its defintely something we should look at.
Jun 20
Benjamin Curtis said,
There’s also a change with has_one associations… they are now validated by default, and there’s no option to turn off that validation. I blogged about it here.
Jun 20
Gregg Pollack said,
Regarding partial or dirty updates, modifying an attribute in place will not get saved automatically. If you did this:
Nothing will be saved.. Nothing! You won’t even see save get called! If you’re not using = to set the variable, you’ll need to either turn partial updates off, or do this:
Kinda nutty eh?
Jun 21
Collin VanDyck said,
You definitely saved me some time with the will_paginate plugin. Thanks!
Jun 22
Tom H said,
Thanks very much for this post. It was badly needed.
A number of people have commented elsewhere on the various gotchas of partial updates; I would argue that in most cases, this is an optimization that provides little or no benefit. Since it can be turned on on an as-needed basis, I think turning them off in environment.rb is the right thing to do for most users. Ryan Bates linked some of this conversation on his RailsCast post on partial updates.
Jun 24
Nate said,
Watch our for validates_uniqueness_of and acts_as_paranoid. These used to be able to work together in older versions of rails, but validates_uniqueness_of got changed so that if you delete an object that’s paranoid, you still won’t be able to create another object that say has the unique property. For example, delete an old user that’s paranoid, and you won’t be able to create another user with that same login. I believe a fair workaround is to add to the :scope of validates_uniqueness_of, the :deleted_at column.
Jun 24
James Hill said,
Heya, perhaps I missed something but isn’t that alias_method meant to:Jun 24
Nate said,
For next RailsConf, Rails 3.x (or whatever) should try and release a week before so that during RailsConf there can be some kind of “upgrading hack fest” where everyone can sit around and yell out which plugin or which feature doesn’t work in their app quite the same anymore and they can collaborate in small groups on the fix/workaround asap. I don’t think this specifically was run in 2008 but it might be a nice focus of a hack fest. These upgrades are getting harder and harder….......
Jun 25
Michael Hartl said,
It’s worth noting that you might have a problem installing the newer will_paginate from GitHub if you’re using an older version of RubyGems. This happened to me with RubyGems v1.1.0:
Updating to the latest version fixed the problem:
Jun 26
fred said,
You don’t have to go quite so manual with the attribute filtering, as Hash has except/slice, so for exampleJun 27
Florian Aßmann said,
`render :partial => ‘xyz’, @collection` now starts xyz_counter at 1 and is nowhere documented, sucks imho…
Jun 27
fred said,
Florian – that has been fixed both on edge and on the stable branch
Sorry, comments are closed for this article.
© 2000 - 2009 by thoughtbot, inc.
written by a bushel of tiny robots
Come “ride the toad” on Hoptoad, the app error app.
Thunder Thimble: Brand monitoring for social media.
Widgetfinger: Simple content management for simple websites.
Tee-Bot, funny shirts your friends won't understand!
Umbrella Today: “It’s like totally the simplest weather report ever, Julie.”
Thoughtbot
thoughtbot is a technology consulting firm that provides web application development and design services. We focus on building modern systems, embracing good ideas and delivering elegant solutions.
Interested in learning Rails?
Sign up for our beginning or advanced training.
Archives