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

通过Stimulus控制器提交form_with时出现CSRF令牌验证错误怎么办?

解决form_with结合Stimulus提交时CSRF令牌验证失败的问题

问题根源

当你给form_with设置local: false时,Rails会将表单标记为AJAX提交(依赖rails-ujs),但你在Stimulus控制器里通过event.preventDefault()阻止了默认的submit事件,随后直接调用form.submit()触发的是原生表单提交,而非Rails UJS的AJAX处理逻辑——这会导致请求没有带上Rails验证所需的CSRF请求头,从而抛出Can't verify CSRF token authenticity错误。

解决方案

方案1:用Fetch API手动发送请求(推荐)

放弃直接调用form.submit(),改用Fetch API提交表单数据,并手动带上CSRF令牌:

修改Stimulus控制器的submit方法:

submit(event) {
  event.preventDefault();
  const form = this.formTarget;
  const formData = new FormData(form);

  fetch(form.action, {
    method: form.method,
    body: formData,
    headers: {
      'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
    }
  })
  .then(response => {
    // 这里添加请求成功后的处理逻辑,比如页面跳转或提示
    if (response.ok) window.location.href = response.url;
  })
  .catch(error => console.error('提交失败:', error));
}

方案2:改为普通表单提交

如果不需要AJAX提交,去掉form_with的local: false选项,让表单做普通同步提交:

修改form_with标签:

<%= form_with(model: @example, data: { controller: "nested-form", nested_form_target: "form", action: "submit->nested-form#submit" }) do |form| %>

此时Stimulus里的submit方法可以保留,因为普通提交时,form_with默认生成的authenticity_token隐藏字段会被自动提交,Rails能正常验证。

方案3:触发Rails UJS的AJAX提交逻辑

如果必须保留AJAX提交,不要调用原生form.submit(),而是触发Rails UJS的处理事件:

修改Stimulus控制器的submit方法:

submit(event) {
  event.preventDefault();
  const form = this.formTarget;
  
  // 触发Rails UJS的submit事件(需确保rails-ujs已加载)
  form.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
}

额外说明

你之前手动添加hidden_field_tag :authenticity_token是多余的——form_with默认会自动生成CSRF令牌的隐藏字段,除非你显式设置authenticity_token: false。

内容的提问来源于stack exchange,提问作者Daniel Gaspar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 16:46:19