読者です 読者をやめる 読者になる 読者になる

リア充爆発日記

You don't even know what ria-ju really is.

件数のキャッシュを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 みたいにすればいいと思う。


以上、よろしくおねがいいたします。