提问人:APotato 提问时间:6/5/2014 最后编辑:APotato 更新时间:6/6/2014 访问量:1366
Rails 默认为“text/javascript”内容类型,以响应使用 form_for 构建的不显眼的 JavaScript 表单
Rails Defaults to "text/javascript" Content Type in Response to Unobtrusive JavaScript Form Built With form_for
问:
我正在使用 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 工具时却不是这样。
我很想了解这里发生了什么,以及是否有任何方法可以配置我的应用程序,这样我就不需要编写这些额外的解决方法。
提前感谢好人。
答:
好吧,当我意识到它是莫名其妙的间歇性时,我应该猜到这部分是一个缓存问题。基本上,解决方案只是强制 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
评论