
Written September 3, 2008. Tagged Shell scripting, Rack.
When you visit /page?format=foo (and sometimes /page.foo, depending on the routes) in a Ruby on Rails app, Rails will try to render the action in that format - that is, using the page.foo.erb template.
If you use the
respond_to do |wants|
  wants.html { … }
  wants.xml { … }
endsyntax, requesting an invalid format gives you an empty "406 Not Acceptable" response.
Actions that do not use this syntax, though, will cause an ActionController::MissingTemplate exception – which the user sees as an unsightly "500 Internal Server Error".
That means actions that render implicitly like
def page
  @page = Page.find(:first)
endas well as explicitly like
def page
  @page = Page.find(:first)
  render :layout => 'example'
endI don't want to show the 500 page unless necessary. In this case, a 404 page makes some sense; you could also argue for using a 406 error (for consistency with respond_to, if nothing else).
I added this to my ApplicationController:
# With +respond_to do |format|+, "406 Not Acceptable" is sent on invalid format.
# With a regular render (implicit or explicit), this exception is raised instead.
# Log it to Exception Logger, but show users a 404 page instead of error 500.
rescue_from(ActionController::MissingTemplate) do |e|
  log_exception(e)
  request.format = :html
  render_404
endThe log_exception(e) line should obviously be changed or removed if you don't use Exception Logger, or don't want the errors logged.
render_404 was described in an earlier blog post. If you prefer an empty error 406, a simple
head(:not_acceptable)should do it.
Note that none of this affects the 406 error when passing an invalid format to a respond_to action.