Rails 默认为“text/javascript”内容类型,以响应使用 form_for 构建的不显眼的 JavaScript 表单

Rails Defaults to "text/javascript" Content Type in Response to Unobtrusive JavaScript Form Built With form_for

提问人:APotato 提问时间:6/5/2014 最后编辑:APotato 更新时间:6/6/2014 访问量:1366

问:

我正在使用 Rails 4.1.1 和 Ruby 2.1.2p95。我使用 Slim 作为我的 HTML 模板语言(类似于 HAML)。我使用 Thin 作为我的机架服务器。

我正在尝试制作一个完全 AJAX 的应用程序(我的要求之一是我可能不会重新加载页面)。

问题

我有一个用户注册页面,如下所示:

= form_for( User.new, url: user_path, remote: true ) do |f|
  = f.label :username
  = f.text_field :username, label: true
  = f.label :password
  = f.password_field :password, label: true
  = f.label :password_confirmation
  = f.password_field :password_confirmation, label: true
  = f.submit

我有一个如下所示的 UsersController 操作(出于本示例的目的):

  def create
    render html: "PRETEND A USER WAS CREATED"
  end

我有一个看起来像这样的响应处理程序(这并不重要 - 只要说成功处理程序不会触发而错误处理程序会触发就足够了):

   $("#dynamic_body").on( "ajax:success", "[data-remote]", function( event, data, status, xhr ) {
      $("#dynamic_body").empty();
      $("#dynamic_body").append( data );
   });
   $("#dynamic_body").on( "ajax:error", "[data-remote]", function( event, xhr, status, error ) {
      $("#dynamic_body").empty();
      $("#dynamic_body").append( error );
   });

Rails 发回一个 Content-Type 标头设置为 “text/javascript” 的响应。因此,浏览器尝试将响应解析为 JavaScript,这当然会失败,并导致 AJAX 响应的错误事件而不是成功事件。

我不喜欢的解决方案

我可以通过在 form_for 调用中指定请求 URL 格式来使用 Rails 来明确解决这个问题:

= form_for( User.new, url: user_path( format: :html ), remote: true ) do |f|
  ...

或者通过在控制器操作中显式指定标头:

def create
    render html: "PRETEND A USER WAS CREATED", content_type: :html
end

但我很沮丧,我什至不得不这样做。没有人要求 Rails 返回 javascript 响应。他们自己的文档说控制器默认为“text/html”,这显然在大多数时候是正确的,但在使用他们不显眼的 javascript 工具时却不是这样。

我很想了解这里发生了什么,以及是否有任何方法可以配置我的应用程序,这样我就不需要编写这些额外的解决方法。

提前感谢好人。

JavaScript Ruby-on-Rails AJAX 内容类型 unobtrusive-javascript

评论

0赞 APotato 6/6/2014
这似乎是Chrome的问题。我对Firefox没有这种头痛。使用每个浏览器中的网络分析器,我看到 Chrome 选择将响应视为“text/javascript”,从而导致问题,而 Firefox 将其视为“html”,并且工作正常。然而,仍然不知道原因是什么。在过去的几个小时里,我一直在研究jquery和jquery-ujs文件,但一无所获。更改 JS 中的请求标头或 Rails 应用程序中的响应标头似乎没有效果。此外,该问题是间歇性的。
0赞 APotato 6/6/2014
没关系。一旦我发布该评论,我就会再次开始工作,它适用于 Chrome,不适用于 Firefox。

答:

0赞 APotato 6/6/2014 #1

好吧,当我意识到它是莫名其妙的间歇性时,我应该猜到这部分是一个缓存问题。基本上,解决方案只是强制 Rails 将请求视为 HTML 请求,但如果浏览器在你弄清楚这一点之前已经将响应缓存为 JavaScript,那么在你清除浏览器缓存之前,它将无法工作。

我将以下代码添加到我的 ApplicationController 中:

class ApplicationController < ActionController::Base
  ...

  # These two filters together should ensure we return HTML responses to the browser's AJAX reqeusts.
  before_filter :prevent_caching
  before_filter :default_request_format_html

  ...

  private

  ...

  def prevent_caching
    expires_now
  end

  def default_request_format_html
    request.format = "html"
  end
end

这些是最小的表单,可以根据您的需求进行更智能的设置(例如,有条件地强制请求格式)。回调是更关键的回调 - 如果你从一开始就正确,理论上你不应该需要缓存破坏回调。default_request_format_html