counter_cache 未指定時の NoMethodError を解消
Rails 7.2 以降、has_many / has_one 側で counter_cache: true や counter_cache: { active: false } を指定したとき、デフォルト列名が導出される前に NoMethodError が発生していました。今回の PR はその原因となる式を修正し、デフォルト列名が安全に取得できるようにします。
背景
counter_cache_column は has_many / has_one 側でカウンタ列名を決定するメソッドです。counter_cache && -counter_cache[:column] という式が評価される際、normalize_options により counter_cache[:column] が nil になると -nil が実行され NoMethodError がスローされました。この問題は e79455f3d4 の変更で導入され、v7.2.0 から回帰していました。
技術的な変更
activerecord/lib/active_record/reflection.rb の counter_cache_column メソッド内で、余分な単項マイナス演算子を除去しました。
- -((counter_cache && -counter_cache[:column]) || "#{name}_count")
+ -((counter_cache && counter_cache[:column]) || "#{name}_count")
この変更により、counter_cache[:column] が nil の場合は -nil が評価されず、|| "#{name}_count" のフォールバックが正しく適用されます。belongs_to 側の実装は既に同様のロジックを使用しているため、一貫した挙動が保たれます。
設計判断
既存の counter_cache オプションを変更せずに式だけを修正 する方針が採用されました。counter_cache は常にハッシュに正規化されるため、オプション自体を拡張したり新たなキーを導入する必要はありません。最小限のコード変更で回帰を防ぎ、後方互換性を維持する設計判断です。
まとめ
has_many / has_one 側で counter_cache を指定した際に起きていた -nil に起因するクラッシュが解消され、counter_cache_column はデフォルトの *_count 列名を安全に返すようになりました。既存の API と挙動はそのままで、開発者は安心してカウンタキャッシュを利用できます。