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

jpmobileを使っているRailsアプリケーションにアクションキャッシュを導入する.

Rails プログラミング

Railsにはページキャッシュ,アクションキャッシュ,フラグメントキャッシュという3種類のキャッシュが使える.

ページキャッシュは自由度がない代わりに,えらく速くなるのでオススメなのですが,多少なりともRailsのcontrollerを通って欲しい処理がある場合は難しいです.

そういうときにアクションキャッシュの出番となります.

(ページキャッシュに関しては,割と人気なので,調べればそれなりにいい記事も出てくると思います.)

たとえば,jpmobileを使っているようなアプリケーションでは,デバイスによってレンダリングするテンプレートが異なるので,たとえ静的ページでも簡単にキャッシュすることはできません.

なにせjpmobileはaround_filterなので,application_controllerは絶対に通さないと,機能しません.

ページキャッシュのように,public以下に実体ファイル(.html)を生成してapacheから呼び出すだけだと,railsの機能は使えません.

こういうときにアクションキャッシュを実装します.

ちなみに,アクションキャッシュはbefore_filterと同じような,filterとして扱われるので,caches_actionより前に書いたbefore_filter処理はすべて実行されてから,キャッシュの動作に入ります.

そのため,jpmobileのfilterも機能するわけですね.

では,どうやってデバイスごとにキャッシュしていけばいいのか?

実はアクションキャッシュにはcache_pathというオプションが指定できます.

キャッシュの動作内でjpmobileで分けているのと同じだけ,オリジナルのパスをつけたキャッシュを生成してやればいいわけです.

どこでもいいのですが,ActionController::Baseに以下のようなメソッドを追加します.

で,hoge#indexをキャッシュしたい場合などには

としてやれば,デバイスごとにキャッシュが生成され,デバイスに則したキャッシュを読み込んでくれます.

便利ですね.

cache_pathについては,パラメータも含めてpath指定してやることで,パラメータごとにキャッシュを分けることができたりして,非常に柔軟性が高い便利なキャッシュ機能を作ることができます.

さて,

仕上げにキャッシュを削除しましょう.

ページキャッシュの実体ファイルはpublic以下に生成されていました.

では,アクションキャッシュは?

tmp/cache以下に保存されているのが普通です.

ただし,アクションキャッシュ,フラグメントキャッシュについてはキャッシュ先を変更することができ,memcacheなんかはよく利用されます.

http://rubyist.g.hatena.ne.jp/rochefort/20100313

実体ファイルがある場合は,Railsの外側からでも削除できそうですが,やはりアクションキャッシュ,フラグメントキャッシュとなると削除はRailsからやるのが一般的です.

そのために,expire_action,expire_fragmentなどが用意されています.

これらはよくsweeperに定義して,controllerで呼び出したりして使います.

では,上記のように自前でcache_pathを指定した場合は?

cache_pathを指定してあげないといけません.

(controller: action: の指定だけでは上手く行きませんでした)

つまり,こういうことです.

expire_action "hoge/index_smart_phone"

とすることで,先ほどhoge#indexでキャッシュしたスマホ用のアクションキャッシュを削除しました.

ちなみに,たとえばkaminariやwill_paginateなどでページングを実装しているページを,params[:page]まで考慮してキャッシュした場合……

cache_pathは"hoge/index?page=2_pc"のようになっているかと思います.

これをsweeperで,全ページのキャッシュを削除したい!みたいな要望ってあると思います.

一般的には

expire_action(%r{hoge/index*})

というようにして,正規表現とか使って全部削除できるように設計されています.

ただ,memcacheのように,メモリ上にキャッシュする場合,cache_pathの指定に正規表現は使えません.

http://doruby.kbmj.com/daoka_tips/20100517/Rails_repcached_

なので,どうしてもこればっかりは一個ずつ削除するしかないんですね…….

ちなみにrails consoleから呼び出して,キャッシュの削除を確認したいというマニアックな望みを持った俺は,いろいろと調べたのですがアクションキャッシュは削除できませんでした.

http://apidock.com/rails/ActionController/Caching/Actions/expire_action

簡単に言うと,expire_actionはprotectedメソッドなので,呼び出せませんwwwww

ただ上記のソースを見ればわかるように,pathの形式で渡した際にはexpire_fragmentを実行しているだけなので,cache_pathと同じ文字列をexpire_fragmentで指定してやることで,rails console上でキャッシュ削除ができました.

ちなみにexpire_fragmentはActionController::Baseのメソッドなので,以下のようにして呼び出します.

ActionController::Base.new.expire_fragment "cache_path"