Search code examples
ruby-on-railscounter-cache

Problem with counter_cache implementation


I'm getting 'rake aborted! ... posts_count is marked readonly' errors.

I have two models: user and post.

users has_many posts.

posts belongs_to :user, :counter_cache => true

I have a migration which adds the posts_count column to the users table and then calculates and records the current number of posts per user.

self.up
  add_column :users, :posts_count, :integer, :default => 0

  User.reset_column_information
  User.all.each do |u|
    u.update_attribute( :posts_count, u.posts.count)
  end
end

when I run the migration I get the error. This is pretty clear-cut, of course and if I remove the :counter_cache declaration from the posts model, e.g.

belongs_to :user

the migration runs fine. This obviously, does not make sense because you couldn't really implement it this way. What am I missing?


Solution

  • You should be using User.reset_counters to do this. Additionally, I would recommend using find_each instead of each because it will iterate the collection in batches instead of all at once.

    self.up
      add_column :users, :posts_count, :integer, :default => 0
    
      User.reset_column_information
      User.find_each do |u|
        User.reset_counters u.id, :posts
      end
    end