Easily keep track of rails' relationship count with counter_cache
Your rails server's logs is full of rows like this one:
(0.3ms) SELECT COUNT(*) FROM "comments" WHERE "comments"."post_id" = 1
Or maybe you just want to store the number of children that a parent model holds to do some calculation queries
Setup
Setting up counter_cache is pretty straightforward. It just consists in adding a new field storing a counter value that will be updated every-time a member is added/removed to the collection using ActiveRecord's callbacks.
# app/models/post.rb
class Post < ActiveRecord::Base
has_many :comments
end
# app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :post, counter_cache: true
end
Then we create the migration:
class AddCommentsCountToPosts < ActiveRecord::Migration
def change
add_column :posts, :comments_count, :integer, default: 0, null: false
# Update the counter for existing records
Post.select(:id) do |result|
Post.reset_counters(result.id, :comments)
end
end
end
And that's all we need to do ! :)
Now we can easily do some queries like:
Post.where("created_at > ?", 2.month.ago).average(:comments_count)
Note 1: It also works with polymorphic associations (despite that it seems to need an additional setup
Note 2: the counter is only updated on model's creation and deletion. If you need to change something when it's updated so you will need a workaround like this one or you can use this gem
Credits: ElegantRuby, StackOverflow and Rails guide