控制器无法检测到 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 =&gt; :data =&gt; :type =&gt; :json 作为选项添加到 simple_form_for... @mccannf 也没有帮助。有什么建议我如何检查是否将什么类型的格式发送到我的控制器? :(您可以在控制器中尝试使用logger.debug request.formatlogger.debug request.headers["Content-Type"] 【参考方案1】:

您将format.json|format.htmlremote: 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.htmlformat.json 一起使用 Rails 应用程序中的大多数用例是像往常一样将remote: true 作为控制器请求处理,呈现部分 HTML 模板(即仅响应内容,没有整体页面布局/导航/等)并将其发送回要在弹出窗口中显示的 HTML 大多数人只是简单地处理远程回调并显示一个 JQuery 弹出窗口。所以他们不需要为每个远程表单编写单独的代码 所以默认情况下,Rails 会调用format.html 进行远程请求 如果您特别想要format.json,并且如果您真的想在客户端手动处理 JSON,请相应地更改 URL。但这不是大多数用例 发出 Ajax 请求并不意味着内容类型是 JSON。它是使用 Javascript 发出的 HTML 请求。例如在jquery $.ajax 方法中,检查这两个选项:acceptdataType。如果您真的想发送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 将呈现&lt;template-name&gt;.html.erb。只有当请求格式为 JSON 时,rails 才会渲染&lt;template-name&gt;.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 请求无法指定内容类型

C# MVC Ajax 请求的问题

jQuery AJAX 获取请求无法正常工作,返回值无法在控制台显示

将 Ajax 数据发送到 Laravel 控制器

Laravel - 将 VerifyCsrfToken 添加到控制器获取 ajax 请求

Rails3 中的 Ajax 请求,无法正常工作