Caching, Resources and Fast-CGI in Ruby on Rails

by Jarrett Colby

If you run your Rails app through Fast-CGI, turning on page caching may very well break your resources. Specifically, when you try to create, update, or delete a resource, you'll either see the index or show method instead of what you intended. Here, I show you a fix using .htaccess.

Broken Resources with Caching

map.resources connects multiple actions to the same URL; the only differentation is the HTTP method. For example, consider the following requests:

GET employees/5
PUT employees/5

In theory, the first should invoke EmployeesController#show, and the second should invoke EmployeesController#update. But, if you turn on page caching under Fast-CGI, Apache might just bypass your routes altogether. Look at this line in the standard Rails .htaccess file:

RewriteRule ^([^.]+)$ cache/$1.html [QSA]

Uh-oh. Apache will read this, and for any request to employees/5, it will serve up the file cache/employees/5.html. The request will never be handed off to Rails. This includes POST, PUT, and DELETE requests. Thus, POST requests will send you to the index, while PUT and DELETE requests will send you to the show page for the record.

The Solution

My solution—which may not be the only or best one—is to edit .htaccess so that it's sensitive to request methods. Here's my modified caching code:

RewriteCond %{REQUEST_METHOD} GET
RewriteRule ^$ cache/index.html [QSA]
RewriteCond %{REQUEST_METHOD} GET
RewriteRule ^([^.]+)$ cache/$1.html [QSA]

This tell Apache that it should only look in the cache for GET requests. Obviously, this won't work if you want to use page caching for other request methods—but how often do you need to do that?