Tuesday, May 12, 2009

expires_cache: A simple Ruby on Rails plugin to enable cache expiration from models

Hi all,

It was a very nice work for me to implement caching for our applications, thanks to Ruby on Rails for giving flexibility over everything.

Ruby on rails is the best technology that I have experienced, in fact I am a fan of it, but it stands behind few steps when it comes to the question of performance. Developers tuning their code could improve it a bit. But as far as my experience in Ruby on Rails, I feel caching is one of the best mechanism to improve the performance.

Basically rails provides 3 different kinds of caching. You can find a very good tutorial on rails caching on railsenvy.com.

As explained on railsenvy.com, sweepers provide an alternate mechanism to seperate cache expiration activity from models which are sensitive to model changes. But I felt its too risky to use sweepers when the application gets complicated, where many controllers will be interacting with many models together. Adding sweeper lines at the top of controllers even made the code to look ugly. I felt there could be some automatic mechanism where sweepers would automatically detect which actions of which controllers are updating what models. But since there are no such mechanism at present, I was motivated to find some mechanism. I then came up with a small library which could handle cache expiration activities whenever it is instructed to do so. Later I made it a plugin so that we can reuse it for other applications too.

You can download the plugin from

http://github.com/heurionconsulting/expires_cache

Alternatively you can also clone using "git clone git://github.com/heurionconsulting/expires_cache.git" into your vendor/plugin directory

To expire the caches, use the following methods either inside controllers or inside model call-backs(eg. after_save)

1. expire_page_cache(): This is an alternative to expire_page() of rails used
to expire the pages cached using caches_page

2. expire_action_cache(): This is an alternative to expire_action() of rails used
to expire the pages cached using caches_action

3. expire_fragment_cache(): This is an alternative to expire_fragment() of rails used
to expire the pages cached using cache() helper.

Example
=======
1. To expire a page cache for the controller=>"categories" and action=>"list", from the model category each time when a new category is created or destroyed:

class Category < ActiveRecord::Base

after_save :expire_caches
before_destroy :expire_caches

def expire_caches

expire_page_cache(:controller=>"categories", :action=>"list")

end

end


2. To expire an action cache for the controller=>"categories" and action=>"show", from the model category each time when a category is updated or destroyed:

class Category < ActiveRecord::Base

after_update :expire_caches
before_destroy :expire_caches

def expire_caches

expire_action_cache(:controller=>"categories", :action=>"show", :id=>self.id)

end

end


3. To expire fragment cache:

Lets say the categories list is cached page by page using fragment caching. Following code expires the first page of the fragment cache:

expire_fragment_cache(:controller=>"categories", :action=>"list", :page=>1)

If file store is used for caching, following code expires all the pages of the categories list:

expire_fragment_cache(:controller=>"categories")

Alternatively a group of cached fragments can also be expired using regular expression as shown below:

expire_fragment_cache(%r{categories/*.*})