I did some more research into this issue. While using clear_association_cache
was convenient enough, adding it after every operation that invalidated the cache did not feel DRY. I thought Rails should be able to keep track of this. Thankfully, there is a way!
I will use your example models: A (has many B, has many C through B), B (belongs to A, has many C), and C (belongs to B).
We will need to use the touch: true
option for the belongs_to
method. This method updates the updated_at
attribute on the parent model, but more importantly it also triggers an after_touch
callback. This callback allows to us to automatically clear the association cache for any instance of A whenever a related instance of B or C is modified, created, or destroyed.
First modify the belongs_to
method calls for B and C, adding touch:true
class B < ActiveRecord::Base
belongs_to :a, touch: true
has_many :cs
end
class C < ActiveRecord::Base
belongs_to :b, touch: true
end
Then add an after_touch
callback to A
class A < ActiveRecord::Base
has_many :bs
has_many :cs, through: :bs
after_touch :clear_association_cache
end
Now we can safely hack away, creating all sorts of methods that modify/create/destroy instances of B and C, and the instance of A that they belong to will automatically have its cache up to date without us having to remember to call clear_association_cache
all over the place.
Depending on how you use model B, you may want to add an after_touch
callback there as well.
Documentation for belongs_to
options and ActiveRecord callbacks:
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-belongs_to
Hope this helps!