You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 13:20:28