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 TestStore
class 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.