Rails respond_to gotcha
Ran into this problem during the launch of a new site. We has some innocent looking controller code that looked something like this:
class SitesController < ApplicationController
respond_to :json, :html
def index
expires_in 1.day, :public => true
@sites = Site.all
respond_to do |format|
format.json { render :json => @sites }
format.html
end
end
end
This looks fine, except that a certain version of IE 6 will pass an Accept
header of */*
to URLs that have no extension, such as http://example.com/sites
.
That means Rails will serve of the first format you’ve defined in your respond_to
block, in this case the json
version of sites#index
.
One might say, who really cares if a handful of IE 6 users is getting a browser full of json
instead of my site? I’m not even supporting IE 6 anymore!
A valid argument, except, for this:
expires_in 1.day, :public => true
If you are using a cache such as Memcached, Varnish, or even Akamai in aconfiguration that respects the Cache-Control
headers from your Rails App, one IE 6 user could cache your http://example.com/sites
URL as json
for 24 hours (in this case). Meaning all other users hitting that URL will get json
back instead of html
until the cache expires.
The easy fix:
class SitesController < ApplicationController
respond_to :json, :html
def index
expires_in 1.day, :public => true
@sites = Site.all
respond_to do |format|
format.html
format.json { render :json => @sites }
end
end
end
Make sure html
is the first format in the respond_to
block.