Rails默认为"text/javascript"响应使用form_for构建的非显眼JavaScr

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

本文关键字:quot 构建 for JavaScr form text 默认 javascript Rails 响应      更新时间:2023-09-26

我使用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响应的成功事件。

我不喜欢的解决方案

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

= 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工具时就不是这样了。

我很想知道这里发生了什么,如果有任何方法可以配置我的应用程序,这样我就不需要编写这些额外的变通方法。

提前感谢好心人。

好吧,当我意识到它莫名其妙地断断续续时,我应该猜到这部分是缓存问题。基本上,解决方案只是强制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回调是更关键的一个-如果你从一开始就正确地使用它,理论上你不应该需要缓存破坏回调。