l'essentiel est invisible pour les yeux

Monday, March 26, 2007

[EffectiveRails] Vary(多様)なキャッシュに対応するcache_on_rails.rbを作った。




昨日買った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の実用性はこれから拡張していくけど、アイデアとしては面白いと思うがどうかな?