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

使用Rails Stimulus实现资源删除时遇重定向及重复请求问题

Rails Stimulus + SweetAlert2 删除操作问题排查与修复

问题现象

  1. 书籍资源已成功删除,但页面无重定向、无删除提示,状态保持不变;
  2. 浏览器控制台出现 DELETE http://127.0.0.1:3000/books 404 (Not Found) 错误,Rails日志显示删除书籍后,又发起了一次指向/books的无效DELETE请求。

原因分析

1. 重复404请求问题

你的button_to参数使用错误:button_to的第二个参数应为目标删除URL,但你将method: :delete直接放在该位置,导致生成的表单action指向当前页面路径(如/books),而非单本书籍的删除路径/books/:id。同时,尽管调用了event.preventDefault(),Turbo的表单提交逻辑仍可能被触发,造成Stimulus发起正确删除请求后,又触发了表单对/books的无效请求,最终出现404。

2. 页面不跳转、无提示问题

你通过fetch发起AJAX删除请求,Rails返回的redirect_to是给浏览器的跳转指令,但AJAX请求不会自动执行跳转,也不会处理flash消息,因此页面无变化、无提示。

修复步骤

1. 修正视图中的button_to代码

调整button_to参数顺序,移除turbo_confirm(避免与SweetAlert2冲突),确保表单指向正确的单本书籍删除URL:

<%= button_to "Delete", url, method: :delete, title: "Remove Book",
            form: { data: {
              controller: "sweetalert",
              action: 'click->sweetalert#confirm',
              "sweetalert-item-value": item_name,
              "sweetalert-url-value": url,
            } },
            class: "delete-icon nobutton" do %>
    <svg>......
<% end %>

注意:此处的url需为单本书籍的删除路径,例如book_path(book),确保指向/books/:id而非/books。

2. 完善Stimulus控制器,处理响应与跳转

修改Stimulus代码,彻底阻止默认事件,在请求成功后手动处理提示与跳转:

import { Controller } from "@hotwired/stimulus";
import Swal from "sweetalert2";
import { getMetaValue } from "../helpers/index";
import { Turbo } from "@hotwired/turbo-rails";

export default class extends Controller {
  static values = {
    item: String,
    url: String,
  };

  confirm(event) {
    // 阻止默认行为与事件冒泡,避免表单重复提交
    event.preventDefault();
    event.stopPropagation();
    
    const csrfToken = getMetaValue("csrf-token");

    Swal.fire({
      titleText: "Are you sure?",
      text: `You are about to delete "${this.itemValue}"`,
      icon: "warning",
      showCancelButton: true,
      confirmButtonColor: "#991c00",
      cancelButtonColor: "#407bbf",
      confirmButtonText: "Yes, delete it!",
    }).then(async (result) => {
      if (result.isConfirmed) {
        const response = await fetch(this.urlValue, {
          method: "DELETE",
          credentials: "same-origin",
          headers: {
            "X-CSRF-Token": csrfToken,
            "Accept": "text/html"
          },
        });

        if (response.ok) {
          // 显示删除成功提示
          Swal.fire({
            title: "Deleted!",
            text: `${this.itemValue} has been deleted.`,
            icon: "success"
          });
          // 用Turbo跳转到书籍列表页
          Turbo.visit("/books");
        } else {
          Swal.fire({
            title: "Error!",
            text: "Failed to delete the item.",
            icon: "error"
          });
        }
      }
    });
  }
}

若无需button_to的表单提交逻辑,可换成link_to配合data-turbo-method="delete":

<%= link_to title: "Remove Book",
            url,
            data: {
              turbo_method: :delete,
              controller: "sweetalert",
              action: 'click->sweetalert#confirm',
              "sweetalert-item-value": item_name,
              "sweetalert-url-value": url
            },
            class: "delete-icon nobutton" do %>
    <svg>......
<% end %>

这种方式下,event.preventDefault()会直接阻止Turbo的默认删除逻辑,确保仅在SweetAlert2确认后发起请求。

额外优化:保留Flash消息

若想保留Rails的flash提示,可修改控制器destroy方法返回Turbo流响应,无需手动跳转:

def destroy
  @book.destroy
  respond_to do |format|
    format.html { redirect_to books_path, alert: "Book removed" }
    format.turbo_stream do
      flash.now[:alert] = "Book removed"
      render turbo_stream: [
        turbo_stream.remove(@book),
        turbo_stream.append("flash", partial: "shared/flash")
      ]
    end
  end
end

此时Stimulus请求后,Turbo会自动处理DOM更新与flash消息展示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 11:03:20