views:

221

answers:

2

I have a model and I would like to store ids of associated objects (denormalize) for performance reasons. I have a method which looks like this:

def cache_ids
  self._tag_ids = self.tag_ids
end

I thought I could just run it on before_save, however there is a problem - some of the associated objects might be new records, and therefore they will not have ids.

Then I switched to after_save, but apparently this callback is also triggered before the transaction is committed, so ids are still not set.

At the moment I ended up with:

def save_with_idcache(*args)
  return false unless save_without_idcache(*args)

  cache_ids

  return save_without_idcache(false)
end

alias_method_chain :save, :idcache

Which seems to work but doesn't look very elegant.

Is there any better way? Like, a callback after the object and associated objects are all saved?

Maybe I am missing something obvious.

A: 

Could you use after_create as well? The id will be there.

after_create :idcache
before_save :idcache

protected
def idcache
  unless new_record?
    ...
  end
end
Sam C
+1  A: 

You might try it in reverse - have the associated objects update their parent's _tag_ids in after_create, after_save (if they are removed from the association and/or added to a new one) and after_destroy.

Whether or not this is a better solution would depend on how many of them there are, how much you're moving them around, and how careful you want to be about dirty attributes.

Sarah Mei