query: tag:cache

MerbのCacheはなかなか優れた設計なので面白いのですが、
開発中にログにCache Miss/Hitの具合が分かるように出力してほしかったので、
development環境用のLoggingMemcachedStoreというのを書いてみました。

ruby>>
class LoggingMemcachedStore < Merb::Cache::MemcachedStore
include Extlib::Hook

before :read do |key, params|
if exists?(key, params)
Merb.logger.debug "Cache Hit: #{key}"
else
Merb.logger.debug "Cache Miss: #{key}"
end
end

before :write do |key, data, params, conds|
Merb.logger.debug "Cache Write: #{key}"
end
end
<<--

こんな感じでログに出ます。

pre>>
merb : worker (port 4000) ~ Cache Hit: Plugins#show
merb : worker (port 4000) ~ Cache Write: Plugins#show
<<--

posted by genki genki on Sat 21 Feb 2009 at 01:19 with 0 comments

RailsのCacheSweeperは非常に便利なのですが、
callbackからコントローラのインスタンス変数にアクセスできると
もっと便利になる気がします。

ソースコードを読んでみたら、やっぱりみんなそう思うようで、
assignsメソッドが用意されていました。

rails>>
class PostsSweeper < ActionController::Caching::Sweeper
observe Post

def after_posts_rating
expire_fragment "posts/show/#{assigns(:post).id}"
end
end
<<--

こんな風に書けます。これは便利。

posted by genki genki on Thu 29 Jan 2009 at 06:03 with 0 comments

###caches_pageとの違い
caches_actionはcaches_pageと似ていますが、依然としてすべてのリクエストがAction Packを通って処理されるようになっています。これは認証や他の制限をつけたいときに便利です。

###"/lists"と"/lists.xml"は別々にキャッシュされる
また、http://blog.s21g.com/listsとhttp://blog.s21g.com/lists.xmlは異なるリクエストとして処理され、別々にキャッシュされます。つまり、:action => "lists"のキャッシュが無効になったからといって、:actioin => "list", :format => ":xml"も無効になるわけではありません。

###キャッシュの無効化
expire_actionでキャッシュを無効化できます。Sweepwerを使って処理、タイミングを書く。caches.rbのサンプルを抜き出します。
rails>>
class ListSweeper < ActionController::Caching::Sweeper
observe List, Item

def after_save(record)
   list = record.is_a?(List) ? record : record.list
   expire_page(:controller => "lists", :action => %w( show public feed ), :id => list.id)
   expire_action(:controller => "lists", :action => "all")
    list.shares.each { |share| expire_page(:controller => "lists", :action => "show", :id => share.url_key) }
  end

end

class ListsController < ApplicationController
caches_action :index, :show, :public, :feed
cache_sweeper :list_sweeper, :only => [ :edit, :destroy, :share ]
end
<<--

###Refs
vendor/rails/actionpack/lib/action_controller/caching.rb
http://scottstuff.net/presentations/rails-caching/ かなり詳しい
http://www.ibm.com/developerworks/web/library/wa-rails1/
http://www.hostingrails.com/forums/rails_coding_thread/386

posted by satoko satoko on Sat 28 Jun 2008 at 01:20 with 0 comments

最近は、自分用にRailsの挙動を拡張するために書いた
lib/xxxx_ext.rbが増えてきました。
こういったファイルはconfig/initializer/の直下に
置いても良いのですが、ON/OFFを切り替えやすいので、
config/initializer/libs.rbの中から、require "xxxx_ext"
を呼ぶようにしています。

さて、今回はActiveRecordをさらに便利に使うために、
僕が行っている拡張を紹介します。

lib/active_record_ext.rb

rails>>
module ActiveRecord
class Base
def self.[](arg, *args)
case arg
when Range
find arg.to_a
when Hash
find :all, arg
when :first, :all
find arg, *args
when :last
find(:all, *args).last
when Symbol
send "find_#{arg}", *args
else
find arg, *args
end
end

def update_counters(counters)
  self.class.update_counters id, counters
end

end
end
<<--

どうでしょう、お分かりだと思いますが、ARクラスに
インデクサ (rb_aref) を定義しています。こんな感じに動作します。

pre>>

Site[1].uri
=> "http://www.google.com/"

Site[1,2].map &:uri
=> ["http://www.google.com/", "http://www.wikipedia.org/"]

Site[1..2].map &:uri
=> ["http://www.google.com/", "http://www.wikipedia.org/"]

Site[:last].title
=> "Ruby/Tk チュートリアル"

Site[:by_uri, "http://www.google.com/"].uri
=> "http://www.google.com/"
<<--

実際のアプリケーションコードの中ではあまり使っていないですが、
script/consoleの中で使うのには大変便利です。

最後に、update_countersは、インスタンスメソッドとして
欲しかったので追加しています。
Rails 2.0から仕様が変わった counter_cache については、
日比さんがこちらに記事
既存のモデル/テーブルでcounter_cacheを使う:update_counters
を書いているので参照してみてください。

posted by genki genki on Tue 15 Jan 2008 at 06:20 with 0 comments

javascript_include_tagstylesheets_link_tag
:cache => trueオプションは、複数のassetsファイルを
ひとつのファイルにまとめる事で、サーバへのリクエスト
数を減らすことができる機能です。

何度か実験してみたところ、生成されたキャッシュファイルを
削除して更新するためには、単純にファイルを削除するだけ
ではだめで、APサーバのプロセスを再起動する必要があるようです。

このためには、./script/process/reaper -a graceful
を使う必要があります。タイプするのが面倒なので、
Rakeタスクを作ってみました。

lib/tasks/cache.rake

rails>>
namespace :tmp do
namespace :cache do
desc 'Delete cached asset files'
task :update do
patterns = [
'public/stylesheets/cached_*.css',
'public/javascripts/cached_*.js']
Dir.glob(patterns).each do |path|
rm_rf path
puts "deleted: #{path}"
end
./script/process/reaper -a graceful 2>&1 > /dev/null
puts "script/process/reaper -a graceful"
end
end
end
<<--

生成されるキャッシュファイルの名前を
:cache => "cached_#{controller.controller_name}"
と指定しているため、こんな感じになります。
デフォルトでは、all.cssall.jsとなりますので
適宜読みかえてください。

posted by genki genki on Sat 12 Jan 2008 at 23:09 with 0 comments

cache_fuやmemcachedを使うときに、cacheメソッドがオプションを
受け取ってくれないので不便だなと思っていたのですが、
EdgeRailsでは以下のようなパッチが当たっていて
この問題は解決されているようです。

[PATCH] Rails have poor support to work with memcached

Let's assume we have a caching installation with Nginx used as a frontend. Nginx attempts to get page body by key from memcached. If it succeeds (meaning that the page is in memcached), Rails doesn't get control, making this schema extremely fast, up to 3K requests per second. In case memcached doesn't contain cached page by url as a key, Rails receive control, render page and cache it in memcached in order for the next request to be retrieved from memcached.

現状のリリースバージョンのコードでは、以下のようになっています。

vendor/rails/actionpack/lib/action_view/helpers/cache_helper.rb

rails>>
def cache(name = {}, &block)
@controller.cache_erb_fragment(block, name)
end
<<--

これが、EdgeRailsでは以下のように変更されています。

vendor/rails/actionpack/lib/action_view/helpers/cache_helper.rb

rails>>
def cache(name = {}, options = nil, &block)
template_extension = first_render[/.(\w+)$/, 1].to_sym

case template_extension
when :erb, :rhtml
@controller.cache_erb_fragment(block, name, options)
when :rjs
@controller.cache_rjs_fragment(block, name, options)
when :builder, :rxml
@controller.cache_rxml_fragment(block, name, options)
else
# do a last ditch effort for those brave souls using
# different template engines. This should give plugin
# writters a simple hook.
unless @controller.respond_to?("cache_#{template_extension}_fragment")
raise "fragment caching not supported for #{template_extension} files."
end

@controller.send!("cache_#{template_extension}_fragment", block, name, options)

end
end
<<--

posted by genki genki on Fri 11 Jan 2008 at 05:52 with 0 comments