Rails incorrectly caches RSS feed as HTML

Here’s the scenario: a site with a page which is served in two formats. http://www.example.com/sample returns HTML, and shouldn’t cache it. http://www.example.com/sample.rss returns an RSS feed, which should be cached. In Rails, we should be able to achieve this by including this code at the top of the controller:

caches_page :sample, :if => Proc.new { |c| c.request.format.rss? }

What this is saying is, if the format of the request is rss, cache it; otherwise, don’t. Because this was page cached, it would create a file public/sample.rss which would get returned in response to any requests; deleting this file equates to invalidating the cache.

The symptom we started seeing, irregularly, was that suddenly http://www.example.com/sample would return RSS. This turned out to be because the RSS feed was getting saved in public/sample.html. To solve the problem, we had to figure out how the RSS feed was getting cached as if it was HTML.

The answer turned out to be a poorly-formatted URL. If you request http://www.example.com/sample?format=rss, the response is (correctly) RSS, but the extension of the cached file is (incorrectly) .html.

In order to work around this bug, we removed the caches_page line from the top of the controller, and instead used cache_page within the response block of the action in question. cache_page accepts two parameters, the string to be cached and the key (the path, in this case) to cache it at, so we could force the cache filename.


respond_to do |format|
format.html
format.rss {
render :layout => false
cache_page(@response, "/sample.rss") }
end

The result here is that HTML is never cached (as required), and when RSS is cached, it is always cached with an .rss extension. The drawback is that the funky URL will never get a cache hit; it will always be generated from Rails (and update the cache while it’s at it). However, that’s an acceptable trade-off for not generating bogus cache files in the first place.

The kludgy part of this–aside from needing to do it in the first place–is using @response in the controller, which we’re not supposed to do. I wish there was a more elegant way of getting the content of the response for caching.

I think this is a bug somewhere in Rails’ caching code, but I haven’t yet dug in to see where or how it could be fixed.

One Response to “Rails incorrectly caches RSS feed as HTML”

  1. [...] found lots of articles on caching 1 format and not another – even Rails’ documentation illustrates how to do [...]

Leave a Reply