Search code examples
ruby-on-railsvalidationactiverecordassociationsupdating

Updating AR associations through _id attributes doesn't update associated object (before validation)


Let's say I have two ActiveRecord models: LineItem and Article.

class LineItem < ActiveRecord::Base
  belongs_to :article
  ...
end

I'm experiencing the following behaviour on LineItems (Rails 2.3.11):

>> l = LineItem.new
=> #<LineItem id: nil, article_id: nil, ...>
>> l.article_id=10
=> 10
>> l.article
=> #<Article id: 10, ...>
>> l.article_id=20
=> 20
>> l.article
=> #<Article id: 10, ...>

So if article_id already has a value, a subsequent change doesn't change the article association anymore. (At least not immediately - only after save it has been set to the new value.)

This is causing me problems in my validate method when updating existing LineItems. In my LineItems-Controller I do update like this:

def update
  @line_item = LineItem.find(params[:id])
  @line_item.attributes = params[:data] #params[:data] contains article_id
  ...      
  @line_item.save!
  ...
end

In my LineItem class I have many validations like this (simplified):

def validate
  if self.article.max_size < self.size
    errors.add_to_base("Too big for chosen article.")
  end
end

On updates this validation acts on the 'old' article since the new one is only in self.article_id (but not in self.article) at this point. I could replace self.article with Article.find(self.article_id) in the condition above but this doesn't look like the way it's meant to be.

Is this a bug in rails (2.3.11) or am I doing something wrong? Thanks a lot.


Solution

  • It is not a bug you are encountering, but rather the behaviour of the AR association cache. You can force the association to be reloaded during validation by passing true to the associtaion method: self.article(true).

    You could also clear all cached assocations for a LineItem instance by calling #clear_association_cache.

    UPDATE:

    It actually was a bug, but it has been fixed! (See Alex's comment)