实例公共方法
respond_to(*mimes) 链接
在没有 Web 服务支持的情况下,一个用于收集显示人员列表数据的操作可能看起来像这样:
def index @people = Person.all end
该操作隐式响应所有格式,但也可以显式枚举格式。
def index @people = Person.all respond_to :html, :js end
这是同一个操作,内置了 Web 服务支持:
def index @people = Person.all respond_to do |format| format.html format.js format.xml { render xml: @people } end end
它的意思是,“如果客户端希望在此操作响应中获得 HTML 或 JS,请像以前一样响应,但如果客户端想要 XML,则以 XML 格式返回人员列表。”(Rails 从客户端提交的 HTTP Accept 标头确定所需的响应格式。)
假设您有一个添加新人员的操作,如果其公司不存在,则可以选择创建公司(按名称),在没有 Web 服务的情况下,它可能看起来像这样:
def create @company = Company.find_or_create_by(name: params[:company][:name]) @person = @company.people.create(params[:person]) redirect_to(person_list_url) end
这是同一个操作,内置了 Web 服务支持:
def create company = params[:person].delete(:company) @company = Company.find_or_create_by(name: company[:name]) @person = @company.people.create(params[:person]) respond_to do |format| format.html { redirect_to(person_list_url) } format.js format.xml { render xml: @person.to_xml(include: @company) } end end
如果客户端想要 HTML,我们只需将其重定向回人员列表。如果他们想要 JavaScript,那么这是一个 Ajax 请求,我们将渲染与此操作关联的 JavaScript 模板。最后,如果客户端想要 XML,我们将创建一个新人员的 XML,但有一个技巧:我们还将人员的公司包含在渲染的 XML 中,所以您会得到这样的结果:
<person>
<id>...</id>
...
<company>
<id>...</id>
<name>...</name>
...
</company>
</person>
但是,请注意该操作顶部的额外部分:
company = params[:person].delete(:company) @company = Company.find_or_create_by(name: company[:name])
这是因为传入的 XML 文档(如果正在处理 Web 服务请求)只能包含一个根节点。因此,我们必须重新排列内容,使请求看起来像这样(URL 编码):
person[name]=...&person[company][name]=...&...
以及像这样(XML 编码):
<person>
<name>...</name>
<company>
<name>...</name>
</company>
</person>
换句话说,我们使请求能够处理单个实体的人员。然后,在操作中,我们从请求中提取公司数据,查找或创建公司,然后用剩余数据创建新人员。
请注意,您可以定义自己的 XML 参数解析器,它允许您在单个请求中描述多个实体(例如,将它们全部包装在一个根节点下),但如果您遵循默认设置并接受 Rails 的默认设置,生活会更容易。
如果您需要使用默认不支持的 MIME 类型,可以在 config/initializers/mime_types.rb 中注册自己的处理程序,如下所示。
Mime::Type.register "image/jpeg", :jpg
respond_to 还允许您通过使用 any 为不同的格式指定公共块。
def index @people = Person.all respond_to do |format| format.html format.any(:xml, :json) { render request.format.to_sym => @people } end end
在上面的示例中,如果格式是 xml,它将渲染:
render xml: @people
或者如果格式是 json:
render json: @people
any 也可以在不带参数的情况下使用,在这种情况下,它将用于用户请求的任何格式。
respond_to do |format| format.html format.any { redirect_to support_path } end
格式可以有不同的变体。
请求变体是请求格式的特化,例如 :tablet、:phone 或 :desktop。
我们经常希望为手机、平板电脑和桌面浏览器渲染不同的 html/json/xml 模板。变体使之变得容易。
您可以在 before_action 中设置变体。
request.variant = :tablet if /iPad/.match?(request.user_agent)
在操作中像响应格式一样响应变体。
respond_to do |format| format.html do |variant| variant.tablet # renders app/views/projects/show.html+tablet.erb variant.phone { extra_setup; render ... } variant.none { special_setup } # executed only if there is no variant set end end
为每种格式和变体提供单独的模板。
app/views/projects/show.html.erb app/views/projects/show.html+tablet.erb app/views/projects/show.html+phone.erb
当您不共享任何代码时,您可以使用内联语法简化变体的定义。
respond_to do |format| format.js { render "trash" } format.html.phone { redirect_to progress_path } format.html.none { render "trash" } end
变体也支持格式的公共 any/all 块。
这对于内联都有效。
respond_to do |format| format.html.any { render html: "any" } format.html.phone { render html: "phone" } end
以及块语法。
respond_to do |format| format.html do |variant| variant.any(:tablet, :phablet){ render html: "any" } variant.phone { render html: "phone" } end end
您还可以设置一个变体数组。
request.variant = [:tablet, :phone]
这将与格式和 MIME 类型协商类似。如果没有声明 :tablet 变体,将使用 :phone 变体。
respond_to do |format| format.html.none format.html.phone # this gets rendered end
来源: 显示 | 在 GitHub 上
# File actionpack/lib/action_controller/metal/mime_responds.rb, line 211 def respond_to(*mimes) raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given? collector = Collector.new(mimes, request.variant) yield collector if block_given? if format = collector.negotiate_format(request) if media_type && media_type != format raise ActionController::RespondToMismatchError end _process_format(format) _set_rendered_content_type(format) unless collector.any_response? response = collector.response response.call if response else raise ActionController::UnknownFormat end end