Railsのアクションキャッシュでフィルタチェインを継続してみる

一応、やろうと思えば出来ることまで確認した。

以下、やったことです。

  • 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

以上。

プロフィール

このブログ記事について

このページは、koshigoeが2008年8月 5日 16:15に書いたブログ記事です。

ひとつ前のブログ記事は「/proc/[number]/memの中身を知りたい」です。

次のブログ記事は「『MySQLデータベース構築バイブル』は面白い」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。