ページ全体にいくつかのパーシャルがレンダリングされたホームページがあります。また、セッションヘッダーもあります(ログイン)。部分的にページ付けされた一連の書籍が含まれています。1 週間に 1 回更新されるため、このパーシャルをキャッシュしたいと考えています。
- 質問 1: 特定のパーシャルをキャッシュするにはどうすればよいですか (db をヒットせずに) ?
- 質問 2 : 書籍モデルを更新するときに、キャッシュされたコンテンツを削除 (期限切れ) するにはどうすればよいですか?
ページ全体にいくつかのパーシャルがレンダリングされたホームページがあります。また、セッションヘッダーもあります(ログイン)。部分的にページ付けされた一連の書籍が含まれています。1 週間に 1 回更新されるため、このパーシャルをキャッシュしたいと考えています。
ここで探しているのは、ビュー レイヤーで発生するフラグメント キャッシングです。保存されたコンテンツのフラグメント キャッシングと期限切れは、驚くほど簡単に実行できます。書籍のリストがあるので、ビューが次のようになっているとします。
<ul>
<% @books.each do |book| %>
<li><%= book.name %></li>
<% end %>
</ul>
このビットだけのキャッシュを有効にするには、次のようにラップしcache
ます。
<% cache do %>
<ul>
<% @books.each do |book| %>
<li><%= book.name %></li>
<% end %>
</ul>
<% end %>
もちろん、これはキャッシュに名前を付けたり、何か特別なことをしたりするわけではありません... Rails はこのキャッシュ フラグメントに一意の名前を自動選択しますが、あまり役に立ちません。もっとうまくやることができます。DHH のキーベースのキャッシュ有効期限テクニックを使用して、キャッシュにその内容に関連する名前を付けましょう。
<% cache ['book-list', *@books] do %>
<ul>
<% @books.each do |book| %>
<li><%= book.name %></li>
<% end %>
</ul>
<% end %>
引数をキャッシュに渡すと、指定された引数からキャッシュ キーが構築されます。文字列は直接渡されます。そのため、ここでは、キャッシュは常に「book-list」で始まります。これは、同じコンテンツを別のビューでキャッシュしている可能性のある他の場所とのキャッシュの衝突を防ぐためです。@books 配列の各メンバーに対して、Rails はcache_key
: を呼び出します。ActiveRecord オブジェクトの場合、モデル、ID、そして重要なことに、オブジェクトが最後に更新された時刻で構成される文字列が生成されます。
これは、オブジェクトを更新すると、このフラグメントのキャッシュ キーが変更されることを意味します。つまり、自動的に期限切れになります。本が更新されると、このキャッシュ ステートメントは存在しないキーを検索し、存在しないと判断して新しいコンテンツを入力します。古くて古いコンテンツは、メモリまたは年齢の制約によって削除されるまでキャッシュ ストアに残ります (memcached はこれを自動的に行います)。
私はこの手法を多くのプロダクション アプリケーションで使用していますが、非常にうまく機能します。詳細については、37signals の投稿を確認してください。Railsでの一般的なキャッシング情報については、Ruby on Rails キャッシング ガイドを参照してください。
「コンピュータ サイエンスには、キャッシュの無効化と名前付けという 2 つの難しい問題しかありません。」
-- フィル・カールトン
キャッシング
Rails Guide to cachingは、 Railsが提供するビルトイン キャッシング戦略の入門として最適です。とにかく、キャッシュへの私の非常に簡単なアプローチがここにあります
# _partial.html.erb
<% cache(some_key, :expires_in => 1.week) do %>
<%# ... content %>
<% end %>
現在、some_key
一意である限り、一部は任意の文字列にすることができます。しかし、もう一度、もう少し賢くして、キーが本のリストに依存するようにしましょう。返されたクエリの配列を実際に渡し、その各エントリに対してbooks
rails 呼び出しを行い、最終的にこのコレクションの一意のキーを構築するとします。cache_key
したがって、コレクションが変更されると、キーが変更されます。これcache_key
は、すべてのモデルに実装されているためActiveRecord::Base
、すべてのモデルで使用できるためです。さらに、利用可能な場合はタイムスタンプも使用します。
しかし、これもまた、リクエストが行われるたびにデータベースにヒットします。コードでも同じ:
# controller_method
@weekly_books = Books.where 'condition'
# _partial.html.erb
<% cache(@weekly_books) do %>
<%# ... content %>
<% end %>
頻繁にデータベースにヒットするのを避けるために、呼び出しをラップすることでクエリ自体をキャッシュすることもできます:
# Book.rb
def self.weeklies
Rails.cache.fetch("book_weeklies", :expires_in => 1.day) do
Books.where 'condition'
end
end
# controller_method
@weekly_books = Books.weeklies
# _partial.html.erb
<% cache(@weekly_books) do %>
<%# ... content %>
<% end %>