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.

Ben Marini

  • software craftsman
  • san francisco, ca

Rails respond_to gotcha
06 Sep 2011
Rails 3 modularity
30 Dec 2010
Rails 3 routing DSL implementation
29 Dec 2010
A DSL implementation based on Bundler
28 Dec 2010
The case for case statements
18 Apr 2009