おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

カウンターキャッシュの初期値を設定するときの落とし穴

後づけでカウンターキャッシュのカラムを追加する場合、初期値を設定してあげないといけませんよね。僕はマイグレーション中に次のように書きました。

class AddCommentsCountToIdeas < ActiveRecord::Migration
  def change
    add_column :ideas, :comments_count, :integer, default: 0

    reversible do |dir|
      dir.up do
        Idea.all.each do |idea|
          idea.update!(comments_count: idea.comments.count)
        end
      end
    end
  end
end

これでマイグレーションを実行したのですが、なぜか Idea#comments_count はすべて 0 です。なぜでしょうか。

よくよくRailsのドキュメントを読むとちゃんと書いてありました。belongs_to メソッドの counter_cache オプションのところ。

Note: Specifying a counter cache will add it to that model's list of readonly attributes using attr_readonly.

というわけで Idea#comments_count は readonly なカラムになっていたのでした。ちゃんとカウンターキャッシュをリセットする reset_counters というメソッドがあるので、次のようにして解決。

Idea.all.each do |idea|
  Idea.reset_counters(idea.id, :comments)
end