---
title: 'The Accept: header vs. #caches_page'
teaser:
tags: web,rails,performance
author: Mike Burns
published_on: 2008-10-21
---

In this example we're going to have an <abbr title="Extensible Markup
Language">XML</abbr> <abbr title="Application Programming Interface">API</abbr>
on `FontsController#index`. A `GET` to `/fonts.xml` will produce a list of every
`Font` in the database, along with all its information (name, thumbnail, a list
of ligatures, price, license, and so on).

This is a long list. Luckily it's just for the <abbr title="Application
Programming Interface">API</abbr> consumers. The normal <abbr title="HyperText
Markup Language">HTML</abbr> people just request `/fonts` and this gives them a
paginated view of the lovely fonts on our system.

So to speed it up we do some simple caching. In `FontsController`, at the top,
we add this:

    caches_page :index, :if => Proc.new {|c|
      c.request.format.xml?
    }

And magically requests to `/fonts.xml` are cached to `public/fonts.xml`. Lovely!
Thanks, Rails!

## The Problem

So what happens when someone requests `/fonts` with an `Accept: text/xml`
header? You can try it like this:

    curl -H 'Accept: text/xml' http://ihearthelvetica.local/fonts

![No XML][no-xml]

[no-xml]: http://images.thoughtbot.com/ui/2008-10-21-no-xml.jpg

`FontsController#index` uses `#respond_to`, so it sends back the <abbr
title="Extensible Markup Language">XML</abbr> as requested. However,
`#caches_page` saves the <abbr title="Extensible Markup Language">XML</abbr> to
`public/fonts.html`! Now when a user requests `/fonts` from their Web browser,
they're getting back a mess of XML!

No good.

## The Workaround

This is a problem deep in the Rails caching code. As a workaround, try this on
for size:

```ruby
class ApplicationController < ActionController::Base
  before_filter :fix_caching_extension_for_xml

private

  def fix_caching_extension_for_xml
    if request.format.xml?
      ActionController::Base.page_cache_extension = '.xml'
    end
  end
end
```

This manually sets the extension for <abbr title="Extensible Markup
Language">XML</abbr> requests to `.xml`, so that it saves it to the right place.

## The Fix

The other option is to fix this in Ruby on Rails itself. Download [the
patch](http://rails.lighthouseapp.com/projects/8994/tickets/1244) attached to
the ticket I've opened and apply it to an edge version of Rails. The patch has
tests and is more generalized, so if the workaround fails to solve your problem
the patch might.

Leave a comment on [the Lighthouse
ticket](http://rails.lighthouseapp.com/projects/8994/tickets/1244) if the patch
works for you, or if you've encountered this problem. Together, we can.
