Counter caches are really useful to keep a track of the amount of related data a given record has. Unfortunately, it's a delicate setup for has_and_belongs_to_many
relations
I started to implement experimentslabs.com using Ruby on Rails for learning reasons, and I had a hard time implementing counter caches on has_and_belongs_to_many
relations.
First, I tried with callbacks, but the after_destroy
callback was not fired, so the counters were only growing up.
Then, I changed the relations to has_many through: :xxx
, with the idea of putting the counter_cache
declaration in the pivot table. Again, to callback fired on destoy (even with dependent: true
). I hope this is not linked to this open issue from 2014 titling "Fails to invoke after_remove
callback when deleting associated record"
During my research, I found this great post by jjmars, and I finally came to this solution:
# album.rb
class Album < ApplicationRecord
has_many :albums_tags
has_many :tags, through: :albums_tags, dependent: :destroy
end
# tag.rb, contains field "albums_count"
class Tag < ApplicationRecord
has_many :albums_tags
has_many :albums, through: :albums_tags
end
# albums_tag.rb
class AlbumsTag < ApplicationContentRecord
belongs_to :album
belongs_to :tag
after_create :increment_counter_cache
after_destroy :decrement_counter_cache
private
def increment_counter_cache
tag.update(albums_count: (tag.albums_count + 1))
end
def decrement_counter_cache
tag.update(albums_count: (tag.albums_count - 1))
end
end
Hope this helps :)
Leave a comment
You want to react to this content or ask something to the author? Just leave a comment here!
Note that the comments are not publicly visible, so don't worry if you don't see yours.
All the information you give will only be visible to the author. We don't share anything with anyone.