Adding a counter cache to a has_many/belongs_to ActiveRecord relationship after the underlying records have been around awhile is one of those tasks that tends to trip up Rails newbies.
Here's an example migration showing the necessary steps.
- Add the counter_cache column as an integer. (If following normal rails convention, name the column with the plural name of the has_many association followed by _count)
- Make sure that the column is set to disallow null values and defaults to 0.
- Reset the counters for existing records. The reset_counters method is not smart enough to take an array of ids, so you have to call it for each record you want updated.
class AddCommentsCountToNominations < ActiveRecord::Migrationdef self.upadd_column :nominations, :comments_count, :integer, null:false, default: 0# reset cached counts for nominations with comments onlyids = Set.newComment.all.each {|c| ids << c.nomination_id}ids.each do |nomination_id|Nomination.reset_counters(nomination_id, :comments)endenddef self.downremove_column :nominations, :comments_countendend
The :counter_cache option is covered in detail on pages 195-196 of my book The Rails 3 Way, including some interesting gotchas.