昨日買ったBeauty Flowを聞いているとカッコよくて気分がのってきたので、イマイチ使いづらいRailsのキャッシュ周りをEffectiveにしてみた。
cache_on_rails.rb
cache_on_rails API
使用方法
上記のスクリプトを#{RAILS_ROOT}/lib以下に設置してconfig/enviroment.rbの下のほうに次の一行を追加するだけ。
require 'cache_on_rails'
詳しくはソース中のコメント参照。
次の二点を拡張した。
- HTTPリクエストヘッダの値を用いてキャッシュするコンテンツを切り替える。
- ブロックを評価した値をキャッシュのキーとして利用する。返り値が同じ場合は同一のキャッシュされたコンテンツが利用される。
一つ目はHTTPリクエストヘッダの値をキャッシュを生成する際のキーとして利用する。例えばユーザエージェント毎に異なるキャッシュを生成する際は次のように指定する。
ユーザーエージェント別にキャッシュを生成する。
class IndexController < ActionController::Base
caches_action_with_vary :index, :vary => :UserAgent
end
class IndexController < ActionController::Base
caches_action_with_vary :index, :vary => [:UserAgent, :AcceptLanugage]
end
:vary => #{リクエストヘッダ名 or リクエストヘッダ名の"-"を削除して大文字で接続したもの}でキャッシュのキーに影響を与えるヘッダ名を指定する。:vary => [:UserAgent, :AcceptLanguage]のように配列で指定することで複数のリクエストヘッダが一致するリクエストに応じたキャッシュを生成できる。
レスポンスヘッダには、:vary => #{HTTPリクエストヘッダ名}で指定したHTTPリクエストヘッダ名がVaryヘッダに指定して返される。Varyヘッダは大文字・小文字を考慮しない。
Vary: user-agent, accept-language
しかし、これだけではRailsのキャッシュの使い心地はまだまだなので、ロケール別・PCのキャリア別・PC/携帯別といった感じに自由にキャッシュを生成できるようにした。ブロックを評価した値をキャッシュのキーとして利用する。ブロック引数にはコントローラが渡される。
以下の例は、gettext/railsと組み合わせて、ロケール毎にキャッシュが生成されるようにする。
class IndexController < ActionController::Base
caches_action_with_vary :index do |controller|
Locale.current.language
end
end
次の例は、Mobile on Railsを使用して携帯とPCのそれぞれでキャッシュを生成する。
ブロックの評価値をキャッシュのキーとして利用するので、キャリア毎のキャッシュを保存する事も簡単である。
class IndexController < ActionController::Base
caches_action_with_vary :index do |controller|
!! controller.request.mobile? # => true or falseがキャッシュのキーとして利用される。
end
end
Cache on Railsの実用性はこれから拡張していくけど、アイデアとしては面白いと思うがどうかな?