まだ Rails 3.2.16 のままのアプリで cache_digests gem を使って fragment cache を導入してみました。

Rails 4.0 では標準になっているはずなので、 使い方は同じだと思います。

この投稿は Ruby on Rails Advent Calendar 2013 の8日目の記事です。

インストール

まず Gemfile に以下の gem の指定を追加してインストールしました。

Gemfile:

gem 'cache_digests'
gem 'dalli', group: :production

環境設定

キャッシュの影響の確認などのデバッグ用に development 環境でも キャッシュを有効にしました。 ちゃんとキャッシュで来ているかどうかの確認や削除がしやすいように 保存先はデフォルトの :file_store のままにしています。

config/environments/development.rb:

  config.action_controller.perform_caching = true

production 環境では dalli を使って memcached に保存するようにしました。 dalli の設定はこの記事の本題ではないので、 memcached の設定などは他のサイトを参考にしてください。

config/environments/production.rb:

  config.cache_store = :dalli_store

staging 環境もあったので config/environments/staging.rb にも同様の設定をしました。

fragment cache

すでに app/views/comments/_comment.html.hamlapp/views/posts/_post.html.haml のような view を使って render @commentsrender @posts のように使っていたので、

app/views/comments/_comment.html.haml:

- cache comment do
  -# 今までの内容

のように cache comment do ... end で今までの内容をくくるだけでした。 cache メソッド自体の返り値は = で埋め込んだりせずにそのまま呼ぶだけで大丈夫でした。

動作確認

log/developement.log などを fragment で検索してみると

log/developement.log:

Write fragment views/comments/29-20130905083500/96f0ec0ce36af8132826f3bfbe0079db 0.5ms
Read fragment views/comments/30-20130905083518/96f0ec0ce36af8132826f3bfbe0079db 0.4ms

などと記録されていて、キャッシュが使われていることが確認できました。

development 環境では実際のキャッシュファイルは tmp/cache/ 以下にありました。

キャッシュの無効化 (invalidate)

キャッシュが古くなってもう有効ではないという状態にすることを invalidate というと思いますが、 内容が更新された時に古いキャッシュが使われると問題があるので、 その対処をする必要があります。

cache メソッドの引数に ActiveRecord のオブジェクトを渡した時の キャッシュのキーは先ほどの例だと views/comments/:id-:updated_at/:md5 という感じで comment オブジェクトの idupdated_atapp/views/comments/_comment.html.haml の MD5 が使われていて、 view のファイルが変更したり、 comment ファイルの updated_at を更新したりした時に 自動で無効になるようです。

つまり、この view の中で別の partial render を使っていると 反映されないということなので、 内側の方でも cache を使うなどの対処が必要そうです。 実際に _post.html.haml の中で render post.comments のようなことをしました。

さらに以下のように belongs_totouch: true を付けて、 コメントが付いた時に postupdated_at も更新されるようにしました。

app/models/comment.rb:

  belongs_to :commentable, polymorphic: true, touch: true

キャッシュの完全削除

rails consoleRails.cache.clear を実行すれば削除できました。 他の sass などのキャッシュも tmp/cache/ の中にあるので 一緒に削除されてしまうようです。

まとめ

とりあえず使い始めるための最低限の知識をまとめてみました。

後は ASCIIcasts - “Episode 387 - Cache Digests” で説明されている rake cache_digests:nested_dependencies などを知っておけば良さそうです。

Disqus Comments

Kazuhiro NISHIYAMA

Ruby のコミッターとかやってます。 フルスタックエンジニア(って何?)かもしれません。 About znzに主なアカウントをまとめました。

znz znz


Published