件数のキャッシュをcounter_cacheじゃなくてcounter_cultureで
Userに対するフォロワーの数とか、何かの投稿件数とか毎度調べてるとヤバイケースとかではcounter_cacheを使うと思うのだけれど、何かの投稿がステータスを持ってて、それがpublicなときだけカウントしたいときとか、counter_cacheが使えないので自分で実装することになる。
まあ、大した実装じゃないかもしれないけど、counter_cultureを使えばかんたんに実装できる。
https://github.com/magnusvk/counter_culture
使う上での注意点としては、以下の2点くらいかな。
- カウンターのupdateをコミット後に行っているので場合によってはカウントに不整合が起きる
- そのかわりcounter_cacheでは発生しやすいdeadlockが起きない
- polymorphic associationsには対応してない
それ以外は、件数カウントじゃなくて、指定カラムの合計するとかもできるので便利。
条件付きのカウントだとこんな感じ。
Gemfile
gem 'counter_culture', '~> 0.1.19'
Post.rb
counter_culture :user, column_name: Proc.new {|model| model.public? ? 'posts_count' : nil }
xxxxx_create_users.rb
~snip~ t.integer :posts_count, null: false, default: 0 ~snip~
※migrationはcounter_cacheと同じ。
これだけー。
あと、テストを書く人は、上述のとおり、counter_cultureはコミット後にカウントアップ処理を行うので、トランザクショナルなデータ管理方式を使っているとテストが通らない。
なので、Rspec+DBCleanerを使っているのであれば
spec_helper.rb
config.before(:each, truncation: true) do DatabaseCleaner.strategy = :truncation end config.after(:each, truncation: true) do DatabaseCleaner.strategy = :transaction end
などとして、describe "post", truncation: true do みたいにすればいいと思う。
以上、よろしくおねがいいたします。