jquery - 当表单中存在文件字段时,Rails 不发出 Ajax 请求
问题描述
问题总结
根据文档,使用时form_with
,Rails 默认发出 Ajax 请求。我需要一个 Ajax 请求,但我发现了一种情况,改为发出标准浏览器请求。我很想知道我做错了什么以及如何解决它。
期望行为:在表单提交时发出 Ajax 请求,这样我就可以返回仅更改显示页面的一部分的 JavaScript。
当前行为:由于该路由仅适用于 XHR,因此正在发出 404 的标准浏览器请求。(如果我让所有请求都可以访问该路由,则整个页面都会被替换,这仍然是非常不可取的。)
编码
这是生成表单的代码:
<%= form_with(url: restore_path,
method: 'post',
multipart: true,
id: 'restore-form') do %>
<label for="file">Backup file:</label>
<%= file_field_tag 'backup_file', required: true %>
<%= submit_tag('Restore',
id: 'restore-submit-button',
class: 'btn btn-primary',
data: { disable_with: 'Restoring...' }) %>
<% end %>
但是,这不会产生 Ajax 请求。restore_path
是一条仅限 XHR 的路线...
constraints(->(req) { req.xhr? }) do
# other routes snipped for brevity's sake
post 'restore' => 'backups#restore'
end
...并且提交表单会导致 404,因为该请求是标准浏览器请求。
我在尝试调试时发现的一个奇怪现象
如果我将字段从 a 更改file_field_tag
为 a text_field_tag
,则请求将作为 Ajax 提交。当我改变
<%= file_field_tag 'file', required: true %>
至
<%= text_field_tag 'test_field', nil, required: true %>
并保持其他一切不变,按预期发出了 Ajax 请求。生成的 HTML 中的唯一变化(除了真实性令牌的确切值)是
<input type="file" name="file" id="file" required="required">
更改为
<input type="text" name="test_field" id="test_field" required="required">
......正如人们所期望的那样。但是表单提交行为完全改变了。
回购
该项目是开源的;上述代码位于https://github.com/steve-mcclellan/j-scorer/blob/master/app/views/stats/_options.html.erb
我尝试过的另一件事
我从头开始创建了一个小的新 Rails 应用程序,以查看是否可以重现该问题,但我不能。即使存在文件上传,也会发出 Ajax 请求。
停!
我的想法不多了。我究竟做错了什么?当文件字段存在时,如何让我的恢复表单发出 Ajax 请求?
解决方案
知道了。文档假设我将rails-ujs
适配器用于不显眼的 JavaScript(自 Rails 5.1 开始内置)。我的应用程序是在 Rails 4 时代创建的,并使用旧的jquery-ujs
适配器。
浏览器本身不会发送包含文件上传的 Ajax 请求。rails-ujs
有一个内置的解决方法,但jquery-ujs
没有。
从这里开始有两种方法。
长期的解决方案是切换到rails-ujs
目前作为 Rails 的一部分维护的 . (在撰写本文时,jquery-ujs
已经两年半没有更新了。)
不幸的是,这两个适配器有一些接口差异,因此可能需要在整个应用程序的 JavaScript 中进行一些更改。具体见这篇文章。
快速修复?嗯,有一个宝石。(文档表明它适用于 Rails 3,但它对我的应用程序很有吸引力,在撰写本文时它正在运行 Rails 6.0.3.3。)
除了Gemfile
:
gem 'remotipart', '~> 1.4.4'
除了app/assets/javascripts/application.js
(在现有jquery_ujs
行之后):
//= require jquery.remotipart
它有效。该请求是通过 Ajax 发出的。它可以毫无问题地访问我的仅限 XHR 的路线,并呈现仅更新部分页面的 JavaScript 视图。
胜利!
推荐阅读
- python - Python嵌套类:未定义自我
- python-3.x - Flask-socketio 没有收到来自客户端的消息
- javascript - React & Firebase - 进行多个 Firebase 调用并等待所有承诺完成
- python-3.x - 如何解决不正确的出生日期数据
- php - 在 WooCommerce 产品循环上显示可变产品的自定义价格范围
- spring - 如何在spring data jpa中使用和/或条件创建rest API
- ruby-on-rails - React-Rails 6 - 无法导入 node_modules 包
- kubernetes - 在 GKE 中以微秒为单位获取事件的时间戳(观察)
- python - 第 10 行的块标记无效:“endblock”,预期为“empty”或“endfor”。您是否忘记注册或加载此标签?django(蟒蛇)
- azure - 如何使用用于 Azure Blob 存储的新 Java v12 SDK 检索分段的容器列表?