I have a Rails 2.1.2 site that only has html templates e.g. jobs.html.erb, so when I request a restful resource:
www.mysite.com/jobs/1
I was getting non-sensical requests for image format on HTML files, triggerring a 500 with MissingTemplate
. I edicted the following at the end of my action:
def show
# [...]
respond_to :html
end
And now instead of getting error reports, we emit a 406 to that mischievious requester.
You can use Rails Per-Action Overwrite feature. What's this? --> It’s also possible to override standard resource handling by passing in a block to respond_with specifying which formats to override for that action:
class UsersController < ApplicationController::Base
respond_to :html, :xml, :json
# Override html format since we want to redirect to a different page,
# not just serve back the new resource
def create
@user = User.create(params[:user])
respond_with(@user) do |format|
format.html { redirect_to users_path }
end
end
end
:except And :only Options
You can also pass in :except and :only options to only support formats for specific actions (as you do with before_filter):
class UsersController < ApplicationController::Base
respond_to :html, :only => :index
respond_to :xml, :json, :except => :show
...
end
The :any Format
If you’re still want to use respond_to within your individual actions, use the :any resource format that can be used as a wildcard match against any unspecified formats:
class UsersController < ApplicationController::Base
def index
@users = User.all
respond_to do |format|
format.html
format.any(:xml, :json) { render request.format.to_sym => @users }
end
end
end
Ben's solution works.
Consider the responds_to solution, though. It's cleaner since it allows flexibility when you will inevitably need to open up an action for a JavaScript json or xml call. Then you won't have to add
skip_before_filter :allow_only_html_requests, :only => [:show]
I personally like the respond_to block; it's very descriptive.
respond_to do |wants|
wants.html
end
Any format not specified in the block will automatically cause a HTTP 406 Not Acceptable to be returned. That's nice.
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
That will run before all requests and only let those that do not specify format at all, or that specify html format through. All others get 404'd. You can create a public/406.html if you want to return 406 not acceptable.
In your routes you can simply remove the line:
map.connect ':controller/:action/:id.:format'
And the ".xyz" will no longer be routed, resulting in 404 errors/.