Wednesday, December 7, 2011

Rails Counter Cache


Counter cache is a mechanism to cache the counts of associated model. The counter cache works by simply updating a parent model's count of related objects after each save or destroy operation on the child model. It increase the counts when associated object is created and decrease the counts when associated object is destroyed.

Why counter cache?
Many times we need the count's of child objects and we use through association to display counts on view in this case multiple SQL queries are raised just to get counts.
One of the traditional example is to display comment counts with every user.

class User < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :user
end

Now get user records with every user comment counts.

To display this counts what rails did.


To solve this issue we can go for active record counter cache.

How to implement counter cache?
We can implement counter cache in three steps

1) Create migration to add column in user table.
class AddCounterCacheToUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :comments_count, :integer, :default => 0
  end

  def self.down
    remove_column :users, :comments_count
  end
end

2) Update existing record of user for comment counts
class AddCounterCacheToUsers < ActiveRecord::Migration
   def self.up
     add_column :users:comments_count:integer:default => 0
    User.find_each do |user|
      user.update_attribute(:comments_count, user.comments.length)
      user.save
    end
  end

  def self.down
    remove_column :users:comments_count
  end
end

After run the migration.
3) Apply counter cache on comment model.
class Comment < ActiveRecord::Base
  belongs_to :user , :counter_cache => true
end

and replace the code of user index view
  <%=h user.comments.length %>
with
  <%=h user.comments_count %>

Now we can get user comments count from same table with no extra query.