You are here: Browse Railsplugins Acts As Cached
Instead, please try cache_fu:
$ script/plugin install svn://errtheblog.com/svn/plugins/cache_fu
http://errtheblog.com/post/4872
\ acts_as_cached /
A plugin which allows you to cache any Ruby object with memcached.
Mailing List => http://groups.google.com/group/acts_as_cached
Installation Stepserr.the_blog.find_by_title(‘Memcaching Rails’) => http://errtheblog.com/post/27
1. Install memcached.
Download: http://danga.com/memcached/download.bml
OSX needs libevent: http://www.monkey.org/provos/libevent/
OSX needs this too: http://blog.segment7.net/articles/2006/03/02/fast-memcached-on-os-x
2. Install memcached-client.
$ sudo gem install memcached-client
3. Install this plugin.
$ cd RAILS_ROOT
$ ruby script/plugin install svn://errtheblog.com/svn/plugins/acts_as_cached
4. Start memcached
$ memcached -vv
5. Start rails. Enjoy.
topfunky has a great writeup on memcached here: http://nubyonrails.com/articles/2006/08/17/memcached-basics-for-rails
Please read the note below about setting up CACHE and MemCache.new. You don't need to do that with acts_as_cached.
UsageAfter installation you will notice memcached.yml in your config/ directory. This file contains information about your memcached servers. The different configuration options are all represented, so have a look. You do not need to setup MemCache.new in your config files anymore. In fact, get rid of that if you added it after following something like the Rails wiki or topfunky’s guide to install memcached.
=== The Basics
In your class definition, include `acts_as_cached’ as you would with any Rails plugin.
class Story < ActiveRecord::Base
acts_as_cached
end
Your Story class now has a host of new methods. Among them: get_cache
Use get_cache in place of find to retrieve single Story objects from the cache.
Story.get_cache(1) => #<story:0×29761bc>
Use expire_cache to remove an object from the cache.
Story.expire_cache(10002) => “DELETED\r\n”
=== Methods
Class methods: get_cache(id) Checks to see if `id’ is already in the cache. If so, returns it. If not, calls find(id) on itself and caches the result.
expire_cache(id)
Clears the cache for a given object.
reset_cache(id)
Re-sets the cache by calling find(id) and then setting the result to the cache without checking
if the cache already exists.
Instance methods: expire_cache, reset_cache Calling story.expire_cache is the same as Story.expire_cache(story_object.id).
=== Time to Live
Tweak the cache expiration time by setting a ttl method on your class and returning a number of seconds. The default time is 30 minutes.
class Story < ActiveRecord::Base
acts_as_cached
end
def self.ttl
20.minutes
end
=== Callbacks
Ensure your cache is always up to date by utilizing Rails’ callbacks:
class Story < ActiveRecord::Base
acts_as_cached
end
after_save :expire_cache_by_id
before_destroy :expire_cache_by_id
On save, your Story object’s cache will be expired. Same with destroy.
=== Versioning Your Models
In a production environment, you may have multiple instances of cached Story object. What happens when you update the Story class and want to push out changes? All of your cached objects are now stale and may have unstable methods or attributes. To solve this, version your cached objects:
class Story < ActiveRecord::Base
acts_as_cached :version => 1
end
When you make a change, simply increment the version. This will ensure only stories of the same version are retrieved from the cache.
=== Conditions (get_cache-only fake with_scope)
As get_cache calls find on your object, it is possible to ensure object consistency by passing an options hash to acts_as_cached.
class Story < ActiveRecord::Base
acts_as_cached :conditions => ['stories.state = ?', Story::State::Published]
end
Now a call to Story.get_cache(1) will call, behind the scenes, Story.find(1, :conditions => [‘stories.state = ?’, Story::State::Published]) and cache the returned object.
The options hash passed to acts_as_cached will be passed to find() behind the scenes for you. Be careful.
=== Refresh All Cached Objects on Pageload
You may want to immediately see all the freshest data on a page load at any time. To help you out, acts_as_cached models have the skip_cache_gets= setter. Try this:
class ApplicationController < ActionController::Base
before_filter :check_cache_skip
end
def check_cache_skip
returning true do
ActiveRecord::Base.skip_cache_gets = params[:skip_cache] ? true : false
end
end
Now any page loaded with ?skip_cache=1 will pull from your database and skip the cache gets. You may want to add some authentication to this method.
=== Associations
Using the acts_as_cached options hash it is possible to cache associations.
class Story < ActiveRecord::Base
acts_as_cached :include => [ :pages, :category ]
end
Again, a call to Story.get_cache(1) will now call Story.find(1, :include => [ :pages, :category ]) behind the scenes.
If you are caching associations, you will need to put forth some effort to keep your caches up to date. Consider this:
class Story < ActiveRecord::Base
acts_as_cached :include => :author
end
When you call Story.get_cache(1), both story 1 AND that story’s associated author will be cached in the same slab as the story itself. If you have 20 stories and 1 author, that author’s object will be cached in 20 places. It can get stale.
One solution:
class Story < ActiveRecord::Base
acts_as_cached :include => :author
end
def after_save
expire_cache(id)
Author.expire_cache(author_id)
end
You will also need:
class Author < ActiveRecord::Base
acts_as_cached
end
def after_save
expire_cache(id)
stories.each do |story|
Story.expire_cache(story.id)
end
end
This can get unmanageable rather quickly.
Another solution is to not cache associated objects but rather their IDs, and to override the accesor methods:
class Story < ActiveRecord::Base
acts_as_cached :include => :author
end
def author
Author.get_cache(author_id)
end
This ensures only the freshest cache objects are retrieved at any given point.
=== Caching Ruby Objects
Once you’ve installed the plugin, any Ruby object may implement acts_as_cached.
class Song acts_as_cached end
The Reloadable module is included in the class to ensure fresh development reloading (not compatible with edge, yet).
Your class must implement a ‘find’ method. A slightly more complete example:
class Song
acts_as_cached
end
def self.find(id)
"I am song #{id}!"
end
=== Caching Blocks
If you’d like to get crazy, you can pass a block to get_cache(id). The result of the block will be cached.
@songs = Song.get_cache(:all) do
Song.find(:all).to_json
end
=== Caching nil
You can not cache `nil’ as a value. acts_as_cache will convert anything you try to cache as `nil’ into `false’ and warn you. Be alert.
=== Keys
Keys are stored, by default, as app-ENVIRONMENT:CLASS:ID. So in development mode a call of Story.get_cache(5) will look for app-development:Story:5.
If you use the :version option, you’ll get something like app-development:Story:v2:5.
=== Cache Size
The default memcached slab (item) size is one megabyte. It is possible to change this but only by recompiling memcached. It is recommended you be mindful of what you cache. Think! Watch your logs.
=== Other Options
It is possible to use something besides memcached as a cache store. Simply pass in your object to your acts_as_cached call via the :store key.
class Post < ActiveRecord::Base acts_as_cached :store => $alternate_store end
Your cache must respond to two methods: set and get. An example:
class MemCacheMock < Hash
def set(key, data, expiry = 0)
self[key] = data.dup rescue data
end
end
def get(key)
self[key]
end
class Post < ActiveRecord::Base
acts_as_cached :store => MemCacheMock.new
end
== Useful Memcached Links
- http://errtheblog.com/post/27
- http://jehiah.com/projects/memcached-win32/
- http://danga.com/memcached/download.bml
- http://www.monkey.org/provos/libevent/
- http://blog.segment7.net/articles/2006/03/02/fast-memcached-on-os-x
- $ sudo gem install memcache-client-stats
/ .by. \
Chris Wanstrath, Tim Myrtle, PJ Hyett => chris[at]ozmm[dot]org
NOTE: This description has been extracted from the Plugin README and so the formatting may need updating to make browser friendly