acts_as_cachedを使う

ActiveRecord をキャッシュしたい、そんなあなたに acts_as_cached。

1. Install memcached.

http://www.danga.com/memcached/download.bml
より memcached の最新版をインストール。
途中、libevent が必要だったので、こっちを先にインストールしておく。



2. Install memcache-client.

$ sudo gem install memcache-client

参考にしたドキュメントには memcached-client って書いてあったけど、これ間違い。d いらない!



3. Install this plugin.

$ cd RAILS_ROOT
$ ruby script/plugin install svn://errtheblog.com/svn/plugins/acts_as_cached
$ mv vendor/plugins/acts_as_cached/memcached.yml.default config/memcached.yml

memcached.yml を使用環境に合わせて適当に編集。
cached-model は environment.rb に記述しないといけなかったけど、acts_as_cached は yml。素晴らしい。
ちなみに、デフォルトは以下のようになっている。

defaults:
  ttl: 1800
  readonly: false
  urlencode: false
  c_threshold: 10000
  compression: true
  debug: false
  namespace: app
  sessions: false
  fragments: false
  servers: localhost:11211
  benchmarking: true

development:
  sessions: false
  fragments: false
  servers: localhost:11211

# turn off caching
test:
  disabled: true

production:
  benchmarking: false
  servers:
    - 192.185.254.121:11211
    - 192.185.254.138:11211
    - 192.185.254.160:11211

4. Start memcached.

$ memcached -vv -u ユーザ名

memcachedを起動



5. Start rails. Enjoy.

基本
class Story < ActiveRecord::Base
  acts_as_cached
end

これで、acts_as_cachedのさまざまなメソッドが利用できる。

キャッシュを得たい場合、get_cache を使う。

>> Story.get_cache(1)
=> #<Story:0x29761bc...>   

キャッシュを消したい場合、expire_cache を使う。

>> Story.expire_cache(10002)
=> "DELETED\r\n"
メソッド

Class methods:

  • get_cache(id)

すでにキャッシュが作られてた場合、何もしない。そうではない場合、find(id) を call し、結果をキャッシュする。

  • expire_cache(id)

キャッシュをクリアする。

  • reset_cache(id)

キャッシュをリセットする。


Instance methods:

  • expire_cache, reset_cache

story.expire_cache は Story.expire_cache(story_object.id) と同じ。

生存時間

デフォルトのキャッシュ生存時間は30分だけど、指定も可能。

class Story < ActiveRecord::Base
  acts_as_cached

  def self.ttl
    20.minutes
  end
end
コールバック

コールバックを使用できる。

class Story < ActiveRecord::Base
  acts_as_cached

  after_save     :expire_cache_by_id
  before_destroy :expire_cache_by_id
end

例では、save の後、destroy の前にコールバックを用いてキャッシュをクリアしている。

Conditions

ここからが acts_as_cached の本領発揮。
find の際に conditions が使える。

class Story < ActiveRecord::Base
  acts_as_cached :conditions => ['stories.state = ?', Story::State::Published]
end

Story.get_cache(1) を呼んだ際、

Story.find(1, :conditions => ['stories.state = ?', Story::State::Published])

に展開される!

ページロードしたときすべてのキャッシュをクリア

acts_as_cached model は skip_cache_gets っていう setter があって、新しいデータがいつでも得たいとき、キャッシュしない設定ができる。

class ApplicationController < ActionController::Base
  before_filter :check_cache_skip

  def check_cache_skip
    returning true do
      ActiveRecord::Base.skip_cache_gets = params[:skip_cache] ? true : false
    end
  end
end

?skip_cache=1 のパラメータ付きで呼ばれたらキャッシュしていないデータが得られる。

Associations

なんと、asssociation まで使える。というか、これを使うための、acts_as_memcached

class Story < ActiveRecord::Base
  acts_as_cached :include => [ :pages, :category ]
end

Story.get_cache(1) を呼んだとき、

Story.find(1, :include => [ :pages, :category ])

に展開される。

Story と assosiation している Author があったとして、Author側もキャッシュしたものを得たいとき。

class Story < ActiveRecord::Base
  acts_as_cached :include => :author

  def after_save
    expire_cache(id)
    Author.expire_cache(author_id)
  end
end

class Author < ActiveRecord::Base
  acts_as_cached 

  def after_save
    expire_cache(id)
    stories.each do |story|
      Story.expire_cache(story.id)
    end
  end
end

と書けるけど、効率悪いので、accesor methods を オーバーライドして

class Story < ActiveRecord::Base
  acts_as_cached :include => :author

  def author
    Author.get_cache(author_id)
  end
end

こんな感じにかっこよく書ける。

ブロックを渡す

実はブロックも渡せる。

@songs = Song.get_cache(:all) do
          Song.find(:all).to_json
         end

クレイジーらしいが。

さらに詳しい使い方は、ドキュメントを参照。
日本語にしてみただけではあんまりなので、自分でもいろいろ試してみよう。

参考:http://require.errtheblog.com/filedetails.php?repname=plugins&path=%2Facts_as_cached%2FREADME
acts_as_cached: ActiveRecordを手軽にキャッシュ