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

Rails UJS搭配form_with远程表单 如何中止提交后再正常提交避免循环

问题根源

死循环是因为调用Rails.fire(form, 'submit')触发表单提交时,Rails UJS会再次派发ajax:beforeSend事件,导致你的监听器逻辑被重复执行,不断触发确认弹窗。

可行解决方案

方案1:添加确认状态标记(最简单常用)

给表单添加一个自定义属性作为确认标记,用户确认后标记为已确认,再次触发ajax:beforeSend时直接放行,不阻止提交:

const form = document.getElementById('assign_sessions_to_employees')
form.addEventListener(
  'ajax:beforeSend',
  (event) => {
    // 已经确认过就直接放行,不阻止提交
    if (form.dataset.confirmed) return
    // 未确认就阻止默认提交,弹出确认框
    event.preventDefault()
    swal.fire({
      title: 'Are you sure ?',
      text: `You are about to spend ${expectedExpenditure()} credits.`,
      showCancelButton: true,
    }).then((result) => {
      if (result.isConfirmed) {
        // 标记为已确认
        form.dataset.confirmed = 'true'
        // 重新触发提交,此时下次触发ajax:beforeSend会直接放行
        Rails.fire(form, 'submit')
      }
    })
  }
)

这个方案不需要修改原有事件绑定逻辑,改动最小,也不会影响表单其他提交相关的逻辑。

小提示:如果表单提交失败需要支持重新提交,可以额外绑定ajax:error事件重置标记:

form.addEventListener('ajax:error', () => {
  delete form.dataset.confirmed
})

如果表单提交后页面会刷新或者表单会被重置,也可以在对应逻辑里补充重置标记的代码,避免用户下次提交时不会触发确认。

方案2:使用一次性事件监听器

绑定事件的时候使用{ once: true }参数,让监听器只执行一次,用户确认后触发提交时不会再执行监听逻辑:

const form = document.getElementById('assign_sessions_to_employees')
const confirmBeforeSubmit = (event) => {
  event.preventDefault()
  swal.fire({
    title: 'Are you sure ?',
    text: `You are about to spend ${expectedExpenditure()} credits.`,
    showCancelButton: true,
  }).then((result) => {
    if (result.isConfirmed) {
      Rails.fire(form, 'submit')
    } else {
      // 用户取消的话,重新绑定监听器,方便下次提交时还能触发确认
      form.addEventListener('ajax:beforeSend', confirmBeforeSubmit, { once: true })
    }
  })
}
// 首次绑定一次性监听器
form.addEventListener('ajax:beforeSend', confirmBeforeSubmit, { once: true })

内容的提问来源于stack exchange,提问作者David Geismar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 19:45:04