Rails 7升级后远程表单无法通过Ajax提交问题排查
Rails 6 升级到 Rails 7 后远程表单无法通过 Ajax 提交的问题解决
问题背景
将 Rails 6 应用升级到 Rails 7 后,远程表单调用submit()方法时触发普通表单提交,导致页面重载,无法实现预期的 Ajax 提交及js.erb脚本渲染逻辑。
初始代码与生成 HTML
表单 ERB 代码:
<%= form_with model: EmailTemplate.new, url: preview_send_now_email_templates_path, html: { id: 'emailPreviewForm' }, format: :js, method: :post, remote: true, data: { turbo: false }, authenticity_token: true do |f| %> <input type="hidden" name="email_template_id" value="1234"> <input type="hidden" name="order_id" value="5678"> <% end %>
生成的 HTML:
<form data-turbo="false" id="emailPreviewForm" action="/email_templates/preview_send_now" accept-charset="UTF-8" method="post"> <input type="hidden" name="authenticity_token" value="yaddayadda" autocomplete="off" /> <input type="hidden" name="email_template_id" value="1234"> <input type="hidden" name="order_id" value="5678"> </form>
提交表单的 JS 代码:
document.getElementById('emailPreviewForm').submit();
已尝试的操作及结果
- 在
application.rb中添加config.action_view.form_with_generates_remote_forms = true,未生效 - 添加
local: false后表单生成data-remote="true"属性,路径加入format: :js后 action 变为/email_templates/preview_send_now.js,但调用submit()仍触发普通提交,直接加载渲染后的js.erb文件
当前应用已加载 Turbo,正逐步迁移至 Hotwire 和 Turbo。
解决方法
1. 改用 Rails UJS 触发提交
原生form.submit()会绕过 Rails UJS 的事件绑定,导致无法触发远程提交。使用 Rails UJS 提供的方式触发:
Rails.fire(document.getElementById('emailPreviewForm'), 'submit');
若项目仍依赖 jQuery,也可使用:
$('#emailPreviewForm').submit();
2. 确保 Rails UJS 正确加载
Rails 7 默认使用 Turbo,若需保留传统 UJS 功能,需确认@rails/ujs已正确引入:
- 检查
package.json中是否包含@rails/ujs,未安装则执行yarn add @rails/ujs - 在
application.js中添加初始化代码:
import Rails from '@rails/ujs'; Rails.start();
3. 优化表单配置,明确启用 UJS 并禁用 Turbo
调整form_with参数,确保data-remote="true"和data-turbo="false"正确生成,同时直接指定 JS 格式路径:
<%= form_with model: EmailTemplate.new, url: preview_send_now_email_templates_path(format: :js), html: { id: 'emailPreviewForm' }, method: :post, local: false, data: { turbo: false } do |f| %> <input type="hidden" name="email_template_id" value="1234"> <input type="hidden" name="order_id" value="5678"> <% end %>
4. 基于 Turbo 实现提交逻辑(适配迁移需求)
若正在迁移到 Turbo,可手动拦截表单提交,用 Turbo 发起请求并处理返回的 JS 代码:
const form = document.getElementById('emailPreviewForm'); form.addEventListener('submit', (e) => { e.preventDefault(); Turbo.fetch(form.action, { method: form.method, body: new FormData(form), headers: { 'Accept': 'text/javascript', 'X-CSRF-Token': form.querySelector('[name="authenticity_token"]').value } }).then(response => response.text()).then(jsCode => { // 执行返回的 JS 脚本 eval(jsCode); }); });
内容的提问来源于stack exchange,提问作者phil
相关产品推荐
相关产品推荐

