通过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
相关产品推荐
相关产品推荐

