We are a software consultancy based in Berlin, Germany. We deliver
high quality web apps in short timespans.

Upstream Agile GmbH

Moving from Rails 2.0.x to Rails 2.1 [Updated]

June 04, 2008 by alex

We are in the process of moving our production code from autoki to the shiny new rails 2.1 and thanks to our unit tests/(r)specs we encountered some gotchas and wows we’d like to share.

Here are some things that change in rails you shold be aware of. If you are using custom callbacks for you rails observer you now have to tell rails about these callbacks first. Simply add a define_callbacks :your_callback, :your_other_callback in models with custom callbacks.

class GroupMembership < ActiveRecord::Base

  belongs_to :member, :foreign_key => :user_id, :class_name => 'User'
  ...
  define_callback :after_confirm # required since 2.1

  ...
  def confirm!
    update_attribute :status, 'active'
    callback :after_confirm # custom callback

  end
end

class GroupMembershipObserver < ActiveRecord::Observer
  def after_confirm(group_membership) # will be called from confirm! in the GroupMembership

    some code here
  end
end

The call to register custom template handlers in the enviroment has changed from ActionView::Base.register_template_handler to ActionView::Template.register_template_handler. With a custom handler you can output pdfs for example.

#register a tempalte handler in enviroment.rb or as an initializer

# pdf renderer

require 'pdf_render'
ActionView::Template.register_template_handler 'rpdf', ActionView::PDFRender

Consequently the ActionController::MissingTempalte Error was moved to ActionView::MissingTemplate.

With the new Caching in place the config call changed from fragment_cache_store to cache_store to reflect the new unified caching infrastructure.

If you have included the Observable mixin in one of your ActiveRecord models, like we did before we learned to harness the power of ActiveRecord::Observer, it’s time to abandon these because the changed method overwrites the new changed of ActivRecords dirty tracking. So if your stack trace look similar to this…

NoMethodError: undefined method `each' for true:TrueClass
method attributes_with_quotes in base.rb at line 2574
method update_without_lock in base.rb at line 2479
method update_without_dirty in optimistic.rb at line 70
...

.. it’s Observable overwriting the ActiveRecord changed method.

What also comes with dirty tracking is, that a save call does nothing unless someting really changed. Although this is the desired behavior, it might break logic where you rely on the old behavior, e.g. when you just want to update the time stamps of an object in the database. You can tell the object with attr_name_will_change! that an attribute should be written to the database.

class User < ActiveRecord::Base
  def visit #should set updated at to current time if visited

     updated_at_will_change! #tell the user that updated_at field will change

     self.save
   end
end

Another ActiveRecord change we found is that :dependent => true isn’t supported anymore although I don’t remember a deprecation warning. Just use :dependent => :nullfiy|:delete|:destroy.

class User < ActiveRecord::Base
 has_one :profile, :dependent => true #this will break, use :nullfiy|:delete|:destroy instead

end

But now let’s come to some nice stuff we discovered.

ActiveRecord now complains with a stack level to deep if you have circular dependency behaviors defined, eg. User has_one :profile, :dependent => :destroy and Profile belogs_to :user, :dependent => :destroy. Such logic can just be the result of isolated late night coding, so an error is the desired behavior in my opinion.

Let’s get back to the aforementioned changed method. Because it returns an array of changed field names, it is a good way to fire after save actions only if a specific field changed. For our autoki application it is a good way to fire some image processing task only if the auto picture changed.

class Auto < ActiveRecord::Base
  after_save :build_new_image
  private
  def build_new_image
    regenerate_widget if changed.include?(:image) # only do this when the image was changed

  end
end
end

At the end comes the real nasty stuff. Rails 2.1 really wrecks havoc under the plugins we are using. As you might guess the most have to do with caching.

While the fragement_cache_test plugins error uninitialized constant ActionController::Caching::Fragments::MemoryStore can be fixed relatively easy by changing the base class for the TestStoreclass in frament_cache_test.rb to ActiveSupport::Cache::MemoryStore and the calls to reset have do be changed to clear the timed_fragment_cache plugin and the extended_fragment_cache are rendered useless until updated, which we don’t expect to happen, so we put together the local_cache_plugin as a resplacement for both.

Will_paginate requires an update from git, and it will play nice again. It resides on github now and can be installed with script/install git://github.com/mislav/will_paginate.git thanks to the install script git support.

The paginated search plugin for ferret will require an update too, because of the changes in will_paginate. But it’s still maintained so just grap the new code from the opensoul blog.

So that’s all for now. (Wow this post got big)

We aren’t finish yet so we will post more while we find other noteworthy changes.