[rails]fragment cacheを使ってみる


fragment cacheを使うとテンプレートの一部を部分的にキャッシュすることが可能になります。

Rails3ではfragment cacheの他にpage cache、action cacheがありましたが、Rails4ではpage cache、action cacheが廃止になりました。

Rails3とRails4の場合でfragment cacheを使った際のメモを残しておきます。

Rails3の場合(Rails 3.2.13で確認)

例としてBookの一覧をキャッシュしたい場合を挙げます。

著者ID(author_id)とページ番号(page)毎にキャッシュできるようにしてみます。

テンプレート側では

<% cache(sprintf(Settings.cache_key.book, @author_id, @page), :expires_in => Settings.book.cache_expire) do %>
キャッシュさせたい内容
  <% @books.each do |book| %>
    <%= book.name %>
  <% end %>
<% end %>

とすることで、cache(‘key’) do end ブロック内がキャッシュされます。

また、:expires_in オプションで有効期限を設定できます。

コントローラ側では

class BookController < ApplicationController
  def index
    @author_id = params['author_id'].to_i > 0 ? params['author_id'].to_i : nil
    @page = params['page'].to_i > 0 ? params['page'].to_i : 1

    # キャッシュのチェック
    unless fragment_exist?(sprintf(Settings.cache_key.book, @author_id, @page))
      @books = Book.where(author_id: @author_id).page(@page).per(Settings.book.limit)
    end
  end
end

fragment_exist?で該当キーのキャッシュが存在するかをチェックし、存在しない場合はBookモデルからデータを取得するようにしています。

また、定数情報に関しては、設定ファイルに切り出しておきます。

# config/settings.yml
  cache_key:
    book: 'book_list_%s_%s'
  book:
    limit: 10
    cache_expire: 60*60 # キャッシュ有効期限を1時間に設定

これで該当ページにアクセスするとキャッシュが作成されます。(デフォルトだとtmp/cache/以下にファイルとして保存されます)

開発環境でテストする場合は、config/environments/development.rb の設定を

config.action_controller.perform_caching = true

にするのをお忘れなく。

Rails4の場合(Rails4.0.0で確認)

Rails4の場合も基本的にはRails3と同じ方法ですが、キャッシュキーにdigestが自動付与されるので :skip_digest => true オプションを渡してdigestを付与しないようにしました。

テンプレート側に:skip_digest => true を設定しています。

<% cache(sprintf(Settings.cache_key.book, @author_id, @page), :expires_in => Settings.book.cache_expire, :skip_digest => true) do %>
キャッシュさせたい内容
  <% @books.each do |book| %>
    <%= book.name %>
  <% end %>
<% end %>

コントローラ側も同様に:skip_digest => true を設定しています。

class BookController < ApplicationController
  def index
    @author_id = params['author_id'].to_i > 0 ? params['author_id'].to_i : nil
    @page = params['page'].to_i > 0 ? params['page'].to_i : 1

    # キャッシュのチェック
    unless fragment_exist?(sprintf(Settings.cache_key.book, @author_id, @page), :skip_digest => true)
      @books = Book.where(author_id: @author_id).page(@page).per(Settings.book.limit)
    end
  end
end

これでRails3と4で同様のfragment cacheが使用できました。

キャッシュ周りはきちんと使えるようになりたいです。

参考