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

Rails中Ajax操作后如何保持Bootstrap Collapse组件处于展开状态?

解决Bootstrap Collapse在Ajax评论操作后自动关闭的问题

这个问题的核心原因很明确:你当前的控制器动作在完成评论增删后用了redirect_to root_path,这会触发整页刷新——页面重新加载后,Bootstrap Collapse的展开状态自然就丢失了,所以会自动关闭。而你用remote: true的初衷是做无刷新Ajax操作,所以我们需要调整控制器和视图的逻辑,实现局部更新而非整页跳转。

下面是具体的解决步骤:

1. 修改控制器动作,响应Ajax请求

去掉redirect_to,改用respond_to来处理JS(或Turbo流,如果你用Rails 7+)请求,这样不会刷新整个页面:

Create动作修改:

def create
  @comment = Comment.new(comment_params)
  authorize @comment
  @todo = Todo.find(params[:todo_id])
  @comment.todo = @todo
  @comment.save

  respond_to do |format|
    format.js # 会自动寻找对应的JS视图文件
    format.html { redirect_to root_path } # 保留HTML请求的 fallback
  end
end

Destroy动作修改:

def destroy
  @comment = Comment.find(params[:id])
  authorize @comment
  @todo = @comment.todo # 记录关联的Todo,方便后续局部更新
  @comment.destroy

  respond_to do |format|
    format.js
    format.html { redirect_to root_path }
  end
end

2. 创建JS视图文件实现局部更新

在app/views/comments/目录下创建对应的JS模板,用来更新评论列表,而不刷新整个页面:

create.js.erb(处理添加评论):

// 定位到当前Todo的评论列表
const commentList = document.querySelector(`#todo-<%= @todo.id %>-comments`);
// 插入新评论的HTML
commentList.insertAdjacentHTML('beforeend', `
  <li id="comment-<%= @comment.id %>">
    <%= j @comment.content %>
    <%= j link_to 'delete', comment_path(@comment), method: :delete, data: { confirm: "Are you sure?" }, remote: true %>
  </li>
`);
// 清空评论输入表单(如果有需要的话)
const commentForm = document.querySelector(`#todo-<%= @todo.id %>-comment-form`);
if (commentForm) commentForm.reset();

destroy.js.erb(处理删除评论):

// 移除被删除的评论元素
document.querySelector(`#comment-<%= @comment.id %>`).remove();

3. 调整视图标记,方便JS定位

给你的评论列表和单个评论添加唯一ID,让JS能精准找到要更新的元素:

<ul id="todo-<%= todo.id %>-comments">
  <% todo.comments.each do |comment| %>
    <li id="comment-<%= comment.id %>">
      <%= comment.content %>
      <%= link_to 'delete', comment_path(comment), method: :delete, data: { confirm: "Are you sure?" }, remote: true %>
    </li>
  <% end %>
</ul>

<!-- 如果是添加评论的表单,也要加上remote: true和唯一ID -->
<%= form_with(model: [todo, Comment.new], remote: true, id: "todo-#{todo.id}-comment-form") do |form| %>
  <%= form.text_area :content %>
  <%= form.submit 'Add Comment' %>
<% end %>

(可选)Rails 7+用户用Turbo Stream简化操作

如果你用的是Rails 7及以上版本,可以用Turbo Stream来更简洁地实现局部更新:

控制器修改:

# Create动作
def create
  # ... 之前的代码
  respond_to do |format|
    format.turbo_stream # 寻找turbo_stream视图文件
    format.html { redirect_to root_path }
  end
end

# Destroy动作
def destroy
  # ... 之前的代码
  respond_to do |format|
    format.turbo_stream
    format.html { redirect_to root_path }
  end
end

创建Turbo Stream视图:

app/views/comments/create.turbo_stream.erb:

<%= turbo_stream.append "todo-#{@todo.id}-comments" do %>
  <li id="comment-<%= @comment.id %>">
    <%= @comment.content %>
    <%= link_to 'delete', comment_path(@comment), method: :delete, data: { confirm: "Are you sure?" }, remote: true %>
  </li>
<% end %>
<%= turbo_stream.update "todo-#{@todo.id}-comment-form", "" %>

app/views/comments/destroy.turbo_stream.erb:

<%= turbo_stream.remove "comment-#{@comment.id}" %>

这样调整后,评论的增删操作都会通过Ajax局部更新页面,不会触发整页刷新,Bootstrap Collapse的展开状态也就会保持住了。

内容的提问来源于stack exchange,提问作者Benoît Bargès

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 04:07:46