Rails Page Caching Isn't Hard. Really.
Oct 17, 2006When it comes to making content driven sites with Rails using page caching is essential. It is the single most important thing you can do to make a site quick and responsive.
The Reason
As Rails apps like Typo, Mephisto, and my creation, Simplist prove, there’s a big demand out there for making it easy to publish content to the web.
While CMS tools make publishing easy, it comes at a performance cost. Each page usually requires grabbing content from a database, assembling dynamic page parts, and putting it all together to output to the browser. It usually happens that this repetitive task results in the same output 90% of the time. The only time it really changes is when new content is published.
This is where page caching comes to the rescue. It allows you to output nice, static HTML, but still retain the power of that comes with the dynamic nature of a CMS.
The Caching
Here’s the super easy part. Look at the actions in your Rails app that send published content to the user. Done? Okay, now add this line to the respective controller for each action.
caches_page :my_cool_action
It’s that simple. Now when that action is accessed it will save the html it generates to the public directory. Every time in the future that page is requested it will serve up the pregenerated static HTML instead of running the action again.
For example, let’s say we have a simple index action for our content controller that displays the most recent five posts. Since we only write a few new posts a week, that page doesn’t change often. Here’s how we’d implement page caching for it.
class ContentController < ActionController::Base
caches_page :index
def index
@last_five_posts = Post.find(:all,
:order => "created_on DESC"
:limit => 5
)
end
end
The Expiring
So now here’s the slightly more difficult part. How do we force our index page to regenerate the cached version when we update the content?
First look at your application. What parts change a post? Mostly likely this will be actions like “save”, “update”, etc.
So each time one of those actions successfully completes you’ll want to expire the cached page so it will regenerate next time it’s called.
Back to our content example. Let’s say we have an update action that updates the content of a post. Definitely a candidate for expiring the cache of our index page.
def update
...
if @post.save
expire_page :controller => "content", :action => "index"
end
end
Expire_page works just like url_for in that it should be associated with some route in your routes.rb file. If you’re a bit foggy on routes I wrote about them awhile ago to help clear things up.
Looking Forward
So now we can cache our content heavy pages to increase performance. But what if we have a fairly complex site? Isn’t it a pain to remember to have expire_page calls in all the right places?
You bet’cha. So next time I’ll cover Sweepers, which will make your life a bit easier in that respect.