Obscure Rails bug: respond_to format.any
I found an odd bug in Rails today. Odd, in the sense that it's not so much broken, as working in a way that's different than one would expect.
In a controller, one uses respond_to to present the appropriate response, as determined by the requested mimetype. If you want to respond to a whole clump of mimetypes in the same way, you might expect format.any to act as a catch-all for all the types you didn't already address.
So, for example, if we're writing an authentication system, we want web browsers redirected to the login page. But for non-browsers (eg, curl asking for XML, or Ajax asking for JSON, or some API asking for a vcard, whatever), it doesn't make any sense to direct them to a login page. We should ask them to use http basic authentication.
Here's the way this is handled by the current version of restful_authentication:
Except, this doesn't actually work. If you make a request for a non-html mimetype, you'll get a 406 ("that format doesn't work here anymore"), not a 401 ("unauthorized").
Presently, format.any actually looks something like this:And, if you dig around a little in the mime_responds tests, you'll see that you're supposed to call #any like so:
Which, effectively, makes #any useless as a high-level catch-all for things like #access_denied. It's interesting that you can use it as a sort of multi-type, but that hardly seems the most common application. (Given the scarce documentation and meta-magic shenanigans in MimeType::Responders, I kinda doubt #any is used all that often. I only know about it because of restful_authentication.)
I've created a patch that changes #any's signature. It can now take 0 or any number of arguments. In the case where it has zero arguments, it assumes the mimetype requested (via the Rails-standard format parameter) or the first allowed mimetype (set by the request headers). In other words, it allows code like #access_denied, above from restful_authentication, to work as intended.
If you can, please take a moment to +1 the patch.