Friday, February 20, 2009

Rails, respond_to, IE6, and the Accept Header

Pain...much pain caused by IE6.

If you've worked with respond_to in Rails, you know what a cool idea it is. Provide access to the same resource in different formats based on either the extension on the URL (i.e. http://something/people/1.xml), or based on an HTTP header that your browser send to the web server, called the Accept header.

It sounds good, but in practice there is one particular browser (*cough* IE) that causes problems. I got into it thinking, "I don't need to worry about this 'Accept' header thing. If a user pulls up http://something/people/1 they'll get an HTML version and if they pull up http://something/people/1.xml they'll get an XML version." This fallacious (?!) reasoning works like a champ with Firefox and IE7 (I think it's getting hazy at this point), but IE6 FAIL!

Change the order of my respond_to block? FAIL! How about forcing a sane Accept header? Sweet! It works, until I upgrade rails and now the request headers are frozen. FAIL! (This may have been my problem because I wasn't doing it right, but it doesn't matter, there is a better way.) How about just explicitly specifying the :format for every URL in the application? Annoying, tedious, but it works, until I get a call from a user, "When I search here and click there I get a 'data dump.'" FAIL!

At this point, I may be doing something wrong. Perhaps one of the above solutions "should" have worked, but I'm mad...there has to be a better way. Can't Rails just serve HTML by default and some other format when you specify the extension? Can't Rails just ignore the Accept header? It turns out that there was a commit on June 27, 2008 that did just that. This was supposedly done for Rails 2.2, and I'm running 2.2.2, so why am I not benefiting from it? Because two weeks later it was undone. However, we're on the right track now.

Given that this is such a widely known issue, I don't know why someone hasn't posted the magic solution until now, but here it is...Are you ready? Add this line to config/environments/{test,development,production}.rb:

config.action_controller.use_accept_header = false

There...that was simple. You're welcome.


Pierre said...

Damn, thanks a lot for this advice, I was stuck for days on this problem. This works like a charm...

omega said...

While I sympathize with your issue and I think IE6 leaves no room to budge: We shouldn't abandon standards like accept headers. They are a good thing, and IE6 will eventually need those last few pushes before being totally extinct.

I think it would be nice if rails did select a different template based on the accept headers and mappings between them and mime types. Without even having to call respond_to()...

paul said...

Thanks for your comment. I don't disagree. I would only suggest turning off accept headers when you are forced to support users with IE6 and every one of 6 different solutions have failed. BTW, if anyone has a better, more compatible solution, I'd be more than happy to hear it. (In my case, I'm developing an Intranet app with essentially a 100% IE6 user base. I'm a contractor and all of my clients are government users.)

I'll be glad when enough users upgrade that we can consider IE6 dead, but for now, it's not a perfect world, and we have to jump through all kinds of hoops to support every browser that we can.

Anonymous said...

Thank you for sharing!!! I was going crazy.