views:

2271

answers:

4

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

It renders my job in html, however, if I request:

www.mysite.com/jobs/1.xml

I get the error:

Template is missing Missing template jobs/show.xml.erb in view path c:/workspace/mysite/app/views

What's worse is that I can also request something like

www.mysite.com/jobs/1.xyz

And indeed I see the error:

Template is missing Missing template jobs/show.xyz.erb in view path c:/workspace/mysite/app/views

To stricly present just html content, what is the cleanest and simplest way to tell Rails that I don't want to render anything other than .html.erb files.

It is important to note that:

  • Some of my controller actions contain conditional calls to the render() method whilst others use the default Rails behaviour i.e. if you don't call render() then the template named youraction.html.erb will be rendered.
  • My code does not use the responds_to() method

It would be great if the solution was not at the render/responds_to level as I would have to modify a significant number of actions. Perhaps there is a way to configure Rails so that only html templates are rendered?

+8  A: 

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/.

Toby Hede
+3  A: 

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.

Ben
+2  A: 

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.

Jonathan Julian
Agreed. The responds_to block opens up a world of flexibility, and if you can take the time to add one for .html to each of your controller actions, it's a much more forward-thinking solution.
Ben
A: 

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
Colins
This is Rails 3 only.
Jared
Jared, could you please be more specific which of the three options is Rails 3 only! I'm running on Rails 2.3.4 and the :any Option works.
Colins