I've been struggling a bit with ActionCaching's handling of different
formats - it doesn't seem very well behaved when trying to present a
single resource in different formats. In particular, it only uses the
path to determine the cache extension to use, so trying to do
something like
curl -H "Accept: application/xml" http://foo.com/stuff
is going to read/write from stuff.cache rather than stuff.xml.cache
Also, ActionCachePath uses the controller to figure out the path to
use, even when expiring actions. As such, if you do an xml POST,
expiring the cache with
expire_action :controller => :stuff
is going to affect stuff.xml.cache.
(IIRC, expire_action :controller => :stuff, :format => :xml would
expire the stuff.xml.xml.cache...)
It won't be until we look into our bug, which might be a while for
this project. I've put links for this thread/ticket in our bug report
though, so I'll let you know what we eventually find.
Hi, we work with Chad and we just implemented the fix he was
promising.
The good news is that we did confirm that it's a problem with Rails
core, and we can probably provide a very simple test case to reproduce
it on any Rails app using caching. (Funny thing: we tracked down the
last time it happened in our logs and it turned out the client making
the fatal request was FeedTools, a Ruby library for fetching and
creating RSS type feeds. So in our test, we used FeedTools itself to
reproduce the bug and solve the problem.)
The bad news is that your patch didn't fix the problem. We had to
resort to overriding the cache_page method in our application
controller. Our code is not ready to be rolled back into Rails Core
because it hardcodes only the three mime types we care about instead
of using Mime::Type's lookup feature. A proper patch would take into
account all the possible mime types that are suitable for caching and
it would take someone much more knowledgeable than us about Rails
innards to do it right.
FWIW, here's our monkey patch:
class ApplicationController < ActionController::Base
...
def cache_page(content = nil, options = {})
return unless perform_caching
self.class.cache_page(content || response.body, cache_path)
end
def cache_path
# Note: this is a monkey patch for a bug in Rails caching, see
# http://groups.google.com/group/rubyonrails-core/browse_thread/thread/22430d01c6c4010
cache_path = request.path
extension = {
"application/atom+xml" => ".atom",
"application/rss+xml" => ".rss",
"text/html" => ".html"
}
request.accepts.each do |mime_type|
s = mime_type.to_s
if extension[s]
cache_path += extension[s]
break
end
end
cache_path
end
To reproduce the issue, here's what you do:
1. gem install feedtools
2. clear your cache
3. use FeedTools to hit your page (in our case, /blabs) -- note that
it's not specifying .atom in the URL, but in the Accept header
require 'feed_tools'
feed = FeedTools::Feed.open("http://example.com/blabs"\)
p feed.title
4. Hit your page in a web browser and see that instead of HTML, your
page is XML