Caching with Ruby on Rails
It just needed to happen. The Hardcore Racing eStore seemed slower every day. It started off as just an attempt to cache the make/model dropdown since we now wanted to put it in the search box in the left sidebar, which is visible on every page. It was simply an unrealistic number of queries to build that dropdown—with all the other queries I expected to make for a page’s request.
Read on to learn how I made my site FAST!
With Rails, there are three types of caching. First, there’s page caching. This is the fastest method because the entire generated page from the first request gets stored on the disk inside the document root. So next time the web server receives that request, the file is served right up off the disk without even invoking the rails application. Here’s an example of an imaginary blog application caching a post page:
1 2 3 |
class BlogController < ApplicationController caches_page :post end |
Just one line, and each post page will only be generated once. This is very fast, but if you want to put a “Welcome username” message in the corner of your page, forget it: you can no longer serve up the exact same page to everyone.
The second two methods both use a different way of remembering the html snippit from the first. By default, rails is configured to store these bits right in the running application’s memory.
If page caching is the most general type cache, the next in line is action caching. Action caching is achieved the same way as page caching except you use caches_action instead. In this case, the action’s result will be cached as a fragment. By doing this, the ActionPack is still dispatched, so you can still authenticate before serving up the page. It also affords you the ability to keep dynamic content in the sidebar if need be.
The final type of caching is the most flexible: fragment caching. Watch how easy this is:
blah blah some code to build my complicated dropdown...
Simply by wrapping my output in this way, I’ve told rails to remember what’s generated from inside the code block. By default, this stored in memory, but you can change it if you read the documentation.
The only trick in this last case is to avoid actually executing those costly queries to the database from the controller that you’ve so toiled to prevent! Imagine we were fragment caching our blog post. We only want to query the database if there’s no fragment returned by read_fragment:
1 2 3 4 5 6 7 |
class BlogController < ActionController def post unless read_fragment :action => 'post' @post = Post.find(params[:id]) end end end |
The Other Half of the Equation
So this is all well and good, but what if some of this data changes? We need a way to expire the cached data - remove it from memory, delete the file on the disk - when its data has or potentially has changed. Thankfully, Rails again makes this very easy for you.
Let’s say someone edits the post in our imaginary blog. In our action that saves the changes to the database, we’d just sneak in this line:
|
|
expire_page :controller => 'blog', :action => 'post', :id => post |
Of course, apart from a hash like this, you can also pass expire_cache a string representing the url or even a regular expression to expire pages en masse.
…And people think my job is hard.
3 Comments to Caching with Ruby on Rails
@djthread
Categories
- Audio (18)
- Computers (29)
- DJ Thread (42)
- Drum 'n Bass (49)
- General (106)
- Reviews (26)
- Software (43)
- Stuff (23)
- Technology (7)






I will give it a try. Thanks
I think your "expire_cache" (in "The Other Half of the Equation" section) should be "expire_page", since as far as I can tell, expire_cache doesn’t exist except for on this site.
Cheers for the nice tutorial though!
Thanks for catching that, Dave. I’ve made the correction in the article.