4

Most of my controllers only have meaningful responses in HTML. Consider the following scenario:

I make a simple controller

class FrontController < ApplicationController
  def index
  end
end

and provide an app/views/front/index.html.erb. If I hit that action with Accept: text/html, it renders that template, as expected.

If I hit that action with Accept: application/xml, I want to get a 406 Not Acceptable. Instead, Rails raises an ActionView::MissingTemplate exception, and shows a 500 error:

Missing template front/index, application/index with {:locale=>[:en], :formats=>[:xml], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee]}.


There are two ways I've been able to get a 406 Not Acceptable out of the controller. First, I can use a respond_to block:

class FrontController < ApplicationController
  def index
    respond_to do |f|
      f.html
    end
  end
end

Second, I can use respond_with, though it looks pretty weird in a controller that doesn't represent a resource:

class FrontController < ApplicationController
  respond_to :html

  def index
    respond_with # No arguments, because there's nothing to put here.
  end
end

Either of those will respond to an XML request with a 406. However, both require adding code to every controller action.


Here's what I'd like to be able to do:

  • Ideally, I'd like an action that renders implicitly (with no render call or explicit formats declared) to return 406 if no template is found. That seems like a sensible default for Rails in general, and I'm surprised it doesn't do that already.

  • Failing that, I'd at least like to be able to declare :html as the only acceptable format for all my controllers by default (and let any explicit format declarations in individual controllers and actions override that).

Ideas?

(Rails 4.0.1, Ruby 2.0.0)

Peeja
  • 13,683
  • 11
  • 58
  • 77
  • 1
    This doesn't answer your question, but it contains a lot of related information & might be helpful for others passing by your question: [Methods for limiting the Rails render format to html](http://stackoverflow.com/questions/1671111/methods-for-limiting-the-rails-render-format-to-html). – James Chevalier Jan 27 '14 at 17:22
  • http://stackoverflow.com/questions/4643738/rails-3-respond-to-default-format I think this one is what you're looking for – jinavar1 Jan 27 '14 at 17:56

1 Answers1

2

If you don't want to use responds_to, you can do this:

class ApplicationController < ActionController::Base
  before_filter :allow_only_html_requests

  ...

  def allow_only_html_requests
    if params[:format] && params[:format] != 'html'
      render :file => "#{RAILS_ROOT}/public/404.html"
    end
  end

  ...

end
James Chevalier
  • 10,604
  • 5
  • 48
  • 74
Freddy Wetson
  • 456
  • 1
  • 4
  • 23
  • That's *too* restrictive. I just want `:html`-only to be the default if no other formats are explicitly provided. – Peeja Jan 27 '14 at 17:14
  • 1
    (Also, the response should set the status to `:not_acceptable`, and rendering an HTML response is probably not the best way to respond to a request that specifically asked for something other than HTML.) :) – Peeja Jan 27 '14 at 17:20