If you have 2 models, Video and Category and they have a "has_and_belongs_to_many" relation with each other, how do you perform a touch to invalidate the cache when one of them changes?
You can't put "touch" on them like you can with a one-to-many relation. Now when i change a category name, the videos that belong to that category don't know about the change until i invalidate the cache. My View Templates show the name of the Category for each Video.
On the model that you want to update you can do something like this:
class Video < ActiveRecord::Base
has_and_belongs_to_many :categories,
after_add: :touch_updated_at,
after_remove: :touch_updated_at
def touch_updated_at(category)
self.touch if persisted?
end
end
Now, whenever a category is added to or removed from a video, the video's updated_at timestamp will get updated. You can do the same thing on the category class if you want categories to update when videos are added to or removed from them.
Touch can be used only in two case.
On a record
category = Category.first
category.touch
On a belongs_to relation
belongs_to :category, :touch => true
So if you want to use it on a HABTM relation, I'm afraid that you'll have to do it manually. It could be something like:
class Category
before_save :touch_videos
def touch_videos
videos.touch
end
end
class Video
def self.touch
update_attributes(:updated_at => Time.now)
# or
each { |video| video.touch } # Make a proper touch
end
end
Be aware that if you want to allow Video to touch categories as well, you'll have to find a way to avoid "circular" updates.
each & find_each
If you prefer each over update_attributes, use find_each to load records by batch. This will avoid loading all records at the same time in memory and potentially crash the application. If you don't have 10k records, you probably won't see any difference, but as your table grows, it will get slower or even break if you use each.
find_each(batch_size: 2000) { |video| video.touch }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With