一応、やろうと思えば出来ることまで確認した。
以下、やったことです。
- caches_actionにフィルタチェインを強制的に継続させるオプションを追加
- キャッシュヒット時にフィルタチェインを継続できる仕組みを実装
- performed?でfalseを返すように内部変数をごまかす
- beforeでtrueを返す
- アクション内にキャッシュヒット時の処理を記述
- performed?でtrueを返すように内部変数を戻す
- (おまけで、Content-Typeなどのヘッダをいじくる)
以下のスクリプトを"config/initialize/action_cache.rb"などに書いて、アクションキャッシュを拡張します。
module ActionController::Caching::Actions::ClassMethods def caches_action(*actions) return unless cache_configured? options = actions.extract_options! around_filter(ActionController::Caching::Actions::ActionCacheFilter.new(:cache_path => options.delete(:cache_path), :continue => options.delete(:continue)), {:only => actions}.merge(options)) end end class ActionController::Caching::Actions::ActionCacheFilter alias_method :before_origin, :before def before(controller) result = before_origin(controller) if result == false && @options[:continue] controller.instance_eval { @performed_render = false } return true end return result end end
あとは、コントローラでcaches_actionを使ってキャッシュしてみたりします。
caches_action :action, :continue => true, :cache_path => Proc.new { |c| options = c.params.dup unless c.request.query_string.blank? query_key = Digest::SHA1.hexdigest(QueryString.new(c.request.query_string).to_s) options[:args] << "__query_hash__=#{query_key}" end ActionCachePath.path_for(c, options) }
上記では、クエリストリングもキャッシュキーに含めるために:cache_pathオプションを与えていますが、本筋には関係ありません。QueryStringは正規化用に自前で書いたクラスです。これも気にしないでください。
アクション内でキャッシュヒットかどうかを判断するために以下のように書いてみたりしています。
if rendered_action_cache @performed_render = true return end
以上。

