当表单中存在文件字段时,Rails 不发出 Ajax 请求
Posted
技术标签:
【中文标题】当表单中存在文件字段时,Rails 不发出 Ajax 请求【英文标题】:Rails not making Ajax request when file field is present in form 【发布时间】:2021-03-15 02:05:24 【问题描述】:问题总结
根据the docs,在使用form_with
时,Rails默认发出Ajax请求。我需要一个 Ajax 请求,但我发现了一种情况,改为发出标准浏览器请求。我很想知道我做错了什么以及如何解决它。
期望行为:在提交表单时发出 Ajax 请求,因此我可以返回 javascript,它只会更改显示页面的一部分。
当前行为:标准浏览器请求发出 404 秒,因为该路由仅适用于 XHR。 (如果我让所有请求都可以访问该路由,则整个页面都会被替换,这仍然是非常不可取的。)
代码
这是生成表单的代码:
<%= 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,因为该请求是标准浏览器请求。
我在尝试调试时发现的一个奇怪现象
如果我将字段从 file_field_tag
更改为 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 请求?
【问题讨论】:
【参考方案1】:知道了。文档假设我正在使用 rails-ujs
适配器来实现不显眼的 JavaScript(自 Rails 5.1 开始内置)。我的应用是在 Rails 4 时代创建的,使用旧的 jquery-ujs
适配器。
浏览器本身不会发送包含文件上传的 Ajax 请求。 rails-ujs
有一个内置的解决方法,但 jquery-ujs
没有。
从这里开始有两种方法。
长期的解决方案是切换到rails-ujs
,目前作为 Rails 的一部分进行维护。 (在撰写本文时,jquery-ujs
已经两年半没有更新了。)
不幸的是,这两个适配器有一些接口差异,因此可能需要在整个应用程序的 JavaScript 中进行一些更改。详情请见this article。
快速修复?好吧,有a gem。 (文档表明它适用于 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 视图。
胜利!
【讨论】:
//= require rails-ujs
不能代替 jquery_ujs 工作吗?
@Eyeslandic 它可以工作,但jquery_ujs
和rails-ujs
之间的接口有点不同,所以我需要对现有代码进行多项更改,如下所述: dev.to/nejremeslnici/migrating-from-jquery-ujs-to-rails-ujs-k9m。在某些时候这样做是个好主意,所以我使用的是更新的库,但remotipart
gem 是一个不需要任何进一步更改的插入式补丁。这就是我现在所需要的,至少。
好的,如果它对你有用,那就太好了。
@Eyeslandic 感谢您的意见。我已经编辑了答案以反映这两个选项以及它们的优缺点。以上是关于当表单中存在文件字段时,Rails 不发出 Ajax 请求的主要内容,如果未能解决你的问题,请参考以下文章
当文本字段填充多对多表单时,Rails 3.2 Ajax 更新 Div
当条目字段不可见时,如何隐藏 Xamarin 表单中的错误标签?