控制器无法检测到 ajax 请求
Posted
技术标签:
【中文标题】控制器无法检测到 ajax 请求【英文标题】:Controller can not detect ajax requests 【发布时间】:2013-05-14 07:16:10 【问题描述】:我正在使用 simple_form gem 并生成我指定 remote:true 选项的表单,如下所示:
<%= simple_form_for @webinar, validate: true, remote:true do |f| %>
所以,表单的输出 html 是以下片段:
<form accept-charset="UTF-8" action="/webinars" class="simple_form new_webinar" data-remote="true" data-validate="true" enctype="multipart/form-data" id="new_webinar" method="post" novalidate="novalidate"> ... </form>
正如我所检查的,当使用 remote:true 选项时,使用标准的 form_for 助手将 data-remote='true' 添加到表单中。从生成的 html 中可以看出,当我使用 simple_form gem 时,也有这样的属性。
所以,在我的控制器中,我有:
def create
@webinar = Webinar.new(params[:webinar])
respond_to do |format|
if @webinar.save
format.html redirect_to @webinar, notice: 'Webinar was successfully created.'
format.js
format.json render json: @webinar, status: :created, location: @webinar
else
format.html render action: "new"
format.json render json: @webinar.errors, status: :unprocessable_entity
end
end
end
但是,总是使用 format.html。我做错了什么?
编辑:
我使用了 logger.debug request.format 来检查请求的实际格式是什么,并且在日志文件中它是:
文本/html
所以,问题一定出在 simple_form 生成的表单中 - 当我们有“data-remote=true”时会有什么问题?
【问题讨论】:
您的application.js
中有//= require jquery
和//= require jquery_ujs
吗? `/app/assets/view/webinar' 下是否有 create.js.erb
文件?
是的,我已经准备好了所有这些。我已经成功地对所有操作的部分进行了 ajax 请求,而无需创建和更新。我的 application.html.erb 文件中也有 。实际上,问题在于控制器的行为格式是 html 而不是 js。
您可以尝试将:html => :data => :type => :json
作为选项添加到 simple_form_for...
@mccannf 也没有帮助。有什么建议我如何检查是否将什么类型的格式发送到我的控制器?
:(您可以在控制器中尝试使用logger.debug request.format
和logger.debug request.headers["Content-Type"]
。
【参考方案1】:
您将format.json|format.html
与remote: true
混淆了。两者是不同的。 remote: true
的存在并不意味着 format.json
。
format.json
并不表示该 URL 是通过 javascript 调用的。这仅意味着客户端期望 JSON 输出。即它不指示输入来自哪里,它指示需要什么输出。
remote:true
的一般用途是,您无需重新加载页面,而是将表单作为 Ajax 请求提交,然后在 JQuery 弹出窗口或其他内容中显示响应。但是,如果您想将响应显示为 JQuery 弹出窗口 - 您需要 HTML 输出,而不是 JSON 输出,对吗?
有些人使用remote: true
在弹出窗口中加载 HTML 内容。您的用例是执行remote: true
,但您期望的是 JSON 格式的数据。 Rails 无法为您做出这些决定。默认情况下,它会将请求发送到/webinars
,并期望您处理 HTML 响应。如果您真的想要 JSON 响应 - 然后自定义发布 Ajax 请求的 URL:
simple_form_for @webinar, url: webinar_path(format: :json), .....
如果您执行上述操作,现在网络研讨会控制器将以 JSON 格式调用。
总体:
remote:true
可以与 format.html
和 format.json
一起使用
Rails 应用程序中的大多数用例是像往常一样将remote: true
作为控制器请求处理,呈现部分 HTML 模板(即仅响应内容,没有整体页面布局/导航/等)并将其发送回要在弹出窗口中显示的 HTML
大多数人只是简单地处理远程回调并显示一个 JQuery 弹出窗口。所以他们不需要为每个远程表单编写单独的代码
所以默认情况下,Rails 会调用format.html
进行远程请求
如果您特别想要format.json
,并且如果您真的想在客户端手动处理 JSON,请相应地更改 URL。但这不是大多数用例
发出 Ajax 请求并不意味着内容类型是 JSON。它是使用 Javascript 发出的 HTML 请求。例如在jquery $.ajax
方法中,检查这两个选项:accept
和dataType
。如果您真的想发送Accepts: application/json
标头,那么您必须在发出Ajax 请求时手动指定(或者如果它是Rails 应用程序,则需要以.json
结束URL)。
因此,即使您向/webinars
发出正常的Ajax 请求,例如$.ajax('/webinars', ...)
- 它也不会转到format.json
!它仍然只会转到format.html
。如果你真的想要JSON格式,那么你必须说$.ajax('/webinars', accepts: 'application/json' )
,或者你必须说$.ajax('/webinars.json')
编辑:次要说明
【讨论】:
我最初的需要是能够使用 ajax 提交表单,所以如果有任何错误或数据提交正确,只刷新页面的一部分 - 现在它正在刷新整个页面页。我虽然添加 remote:true 将使我的控制器使用 *.js 部分。对于我的应用程序中的链接,这工作正常,但我想提交表单不是?如果是这样,这是否意味着为了在我有表单时只刷新我的部分页面,我只需要使用 JSON 格式? 使用remote: true
发出 Ajax 请求后,您现在有两种方法来刷新页面的一部分: (1) 从 URL 返回 JSON,在浏览器中解析它并使用更新页面javascript/jquery, OR (2) 从 URL 返回一个部分模板(没有整个网页布局的 HTML 的小 sn-p),显示一个 jquery 弹出窗口。如果您需要 (1) - 您最终将编写更多 javascript 代码,并且类似地在 URL 中您需要将表单的 URL 指定为 /webinars.json
。如果您需要 (2) - 您可以将表单的 URL 称为 /webinars
。
现在,您似乎想做 (1)(返回 JSON),并且您想在浏览器中手动处理 JSON。然后你需要将 simple_form URL 指定为/webinars.json
谢谢,我实际上想要的是 (2) - 渲染部分模板。我将继续寻找为什么它不使用我的 create.js.erb
嗨@gotqn,因为请求格式是HTML - 默认情况下,rails 将呈现<template-name>.html.erb
。只有当请求格式为 JSON 时,rails 才会渲染<template-name>.js.erb
。如果您希望 render
函数显式呈现该 *.js.erb
模板,请参考此答案:***.com/questions/339130/…【参考方案2】:
您似乎没有在生成的表单操作中直接请求 JSON 格式的文档。也许一种选择是使用以下技术在您的路由文件中将:format
设置为json
:http://guides.rubyonrails.org/routing.html#defining-defaults
您还可以通过为 :defaults 选项提供哈希来定义路由中的其他默认值。这甚至适用于您未指定为动态段的参数。例如:
match 'photos/:id' => 'photos#show', :defaults => :format => 'jpg'
Rails 会将 photos/12 匹配到 PhotosController 的 show 动作,并将 params[:format] 设置为“jpg”。
【讨论】:
【参考方案3】:我不敢相信我已经浪费了这么多时间来试图理解为什么 simple_form 没有按预期工作。
最后,看来我已经以正确的方式完成了所有事情,导致问题的原因是:
AJAX 不能用于文件上传。
为了解决我的问题,我只需将以下 gem 添加到我的 Gemfile 中并运行 bundle install 命令:
gem 'remotipart', '~> 1.0'
然后在我的 application.js 文件中添加以下行:
//= 需要 jquery.remotipart
更多信息:
-
remotipart gem
How to upload multiple files using jQuery
【讨论】:
以上是关于控制器无法检测到 ajax 请求的主要内容,如果未能解决你的问题,请参考以下文章
Play1.2.7 中对控制器的 Ajax/Json 请求无法指定内容类型
jQuery AJAX 获取请求无法正常工作,返回值无法在控制台显示