🐘

Active Record の cache_key_with_version を活用したキャッシュ戦略

2024/05/14に公開

cache_key_with_version とは

ActiveRecord モデルのキャッシュキーを生成するためのメソッドです。
https://github.com/rails/rails/blob/6f0d1ad14b92b9f5906e44740fce8b4f1c7075dc/activerecord/lib/active_record/integration.rb#L97

主に以下の3つのインスタンスに対して使用できます。

  • ActiveRecord::Base
  • ActiveRecord::Relation
  • ActiveRecord::Associations::CollectionProxy

それぞれ生成するための材料に違いがあるので、挙動を見ていきましょう。

ActiveRecord::Base

ActiveRecord::Base では、以下の3つを材料にします。

  • モデル名
  • レコードの ID
  • updated_at
> user = User.find 1
> user.updated_at
=> Tue, 14 May 2024 00:11:08.960197000 UTC +00:00

> user.cache_key_with_version
=> "users/1-20240514001108960197"

このように、
{モデルのクラス名}/{レコードの ID}-{updated_at}
の形式で作成されていることが分かります。

ActiveRecord::Relation

ActiveRecord::Relation では、以下の3つを材料にします。

  • クエリの内容(SQL)
  • クエリ結果の数
  • 最も新しいレコードの updated_at
> articles = user.articles.where("title LIKE ?", "%title%")
> articles.class
=> Article::ActiveRecord_AssociationRelation

> articles.count
=> 10

> articles.maximum(:updated_at)
=> Mon, 13 May 2024 23:28:34.308967000 UTC +00:00

> articles.cache_key_with_version
=> "articles/query-e8478f10fdc007c9bd386d1cef3c7c0f-10-20240513232834308967"

このように、
{モデルのクラス名}/query-{クエリのハッシュ値みたいなもの}-{レコード数}-{最も新しいレコードの updated_at}
の形式で作成されていることが分かります。
ちなみにレコード数が0件の場合、以下のような結果になります。

> articles = user.articles.where("title LIKE ?", "%ほげほげほげ%")
> articles.cache_key_with_version
=> "articles/query-075f0b4c7ee7596dbf79f92e12528aad-0"

ActiveRecord::Associations::CollectionProxy

ActiveRecord::Associations::CollectionProxy でも、
ActiveRecord::Relationと同じで以下の3つを材料にします。

  • クエリの内容(SQL)
  • クエリ結果の数
  • 最も新しいレコードの updated_at
> articles = user.articles
> articles.class
=> Article::ActiveRecord_Associations_CollectionProxy

> articles.cache_key_with_version
=> "articles/query-ed4a8a468806a940de4f5a4ed6615d59-10-20240513232834308967"

用途

例えばレコード取得後に重い処理をしている場合、クエリの結果が変わっていなければ304を返したり、
キャッシュの結果を使うようにしたりできます。

Discussion