将 Rails 渲染格式限制为 html 的方法

Posted

技术标签:

【中文标题】将 Rails 渲染格式限制为 html 的方法【英文标题】:Methods for limiting the Rails render format to html 【发布时间】:2010-12-12 20:51:14 【问题描述】:

我有一个只有 html 模板的 Rails 2.1.2 站点,例如jobs.html.erb,所以当我请求一个宁静的资源时:

www.mysite.com/jobs/1

如果我要求,它会以 html 呈现我的工作:

www.mysite.com/jobs/1.xml

我得到错误:

模板丢失 缺少模板 视图路径中的jobs/show.xml.erb c:/workspace/mysite/app/views

更糟糕的是我还可以请求类似的东西

www.mysite.com/jobs/1.xyz

确实我看到了错误:

模板丢失 缺少模板 视图路径中的作业/show.xyz.erb c:/workspace/mysite/app/views

要严格呈现 html 内容,告诉 Rails 我不想呈现 .html.erb 文件以外的任何内容的最简洁和最简单的方法是什么。

需要注意的是:

我的一些控制器操作包含对 render() 方法的条件调用,而其他操作使用默认的 Rails 行为,即如果您不调用 render(),那么名为 youraction.html.erb 的模板将被渲染。 我的代码没有使用 responds_to() 方法

如果解决方案不在 render/responds_to 级别,那就太好了,因为我必须修改大量操作。也许有一种方法可以配置 Rails 以便只呈现 html 模板?

【问题讨论】:

【参考方案1】:

在您的路线中,您可以简单地删除该行:

map.connect ':controller/:action/:id.:format'

并且“.xyz”将不再被路由,导致404错误/。

【讨论】:

删除这一行并不能解决 Rails 3.2.6 中的问题:它已经被注释掉了,但仍然出现 Template Missing 错误。【参考方案2】:

您可以使用 Rails Per-Action Overwrite 功能。这是什么? --> 还可以通过将块传递给 respond_with 来覆盖标准资源处理,并指定该操作要覆盖的格式:

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 选项

您还可以传入 :except 和 :only 选项以仅支持特定操作的格式(就像使用 before_filter 一样):

class UsersController < ApplicationController::Base
  respond_to :html, :only => :index
  respond_to :xml, :json, :except => :show
  ...
end

:任何格式

如果您仍想在个人操作中使用 respond_to,请使用可用作通配符匹配任何未指定格式的 :any 资源格式:

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

【讨论】:

Jared,您能否更具体地说明三个选项中的哪一个仅适用于 Rails 3!我在 Rails 2.3.4 上运行,并且 :any 选项有效。【参考方案3】:

如果您不想使用 responds_to,可以这样做:

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

这将在所有请求之前运行,并且只让那些根本不指定格式或指定 html 格式的请求通过。所有其他人都得到404'd。如果您想返回 406 不可接受,您可以创建一个 public/406.html。

【讨论】:

这实际上并没有返回 404,但它只是将 404.html 呈现为 200 响应。您需要添加:status =&gt; 404(或:status =&gt; :not_found)。同样,对于 406,您需要使用 :status =&gt; 406(或 :status =&gt; :not_acceptable)。 如果请求使用 'accept' 标头来请求响应类型,这也会失败,因为它没有存储在 params 中【参考方案4】:

Ben 的解决方案有效。

不过,请考虑 responds_to 解决方案。它更简洁,因为当您不可避免地需要为 javascript json 或 xml 调用打开一个操作时,它提供了灵活性。那你就不用加了

skip_before_filter :allow_only_html_requests, :only => [:show]

我个人喜欢 respond_to 块;它非常具有描述性。

respond_to do |wants|
  wants.html
 end

块中未指定的任何格式将自动导致返回 HTTP 406 Not Acceptable。挺好的。

【讨论】:

同意。 responds_to 块开辟了一个灵活的世界,如果您可以花时间为每个控制器操作添加一个 .html 文件,这是一个更具前瞻性的解决方案。【参考方案5】:

我收到了对 HTML 文件的图像格式无意义的请求,触发了带有 MissingTemplate 的 500。我在行动结束时制定了以下内容:

def show
  # [...]
  respond_to :html
end

现在我们不会收到错误报告,而是向那个淘气的请求者发出 406。

【讨论】:

以上是关于将 Rails 渲染格式限制为 html 的方法的主要内容,如果未能解决你的问题,请参考以下文章

Rails 以不同的格式渲染动作

Rails:将 API 请求限制为 JSON 格式

Rails slim 将 html 渲染为文本

Rails - 格式和渲染 - 它们是如何工作的?

将 Rails 实体渲染为文件

Rails 渲染不起作用