Rails 7 Turbo问题求助:Todo增删需刷新才生效
Rails 7 Turbo Todo应用:创建/删除后需刷新页面的问题修复
问题场景
在使用Rails 7的Turbo开发Todo应用时,碰到以下异常:
- 创建Todo对象后,必须刷新页面才能看到新条目
- 删除Todo时,同样需要刷新页面才会从列表中消失
尝试过method: :delete和data: {turbo_method: :delete}参数,问题仍未解决,怀疑变量使用有误但无法准确定位。
核心问题分析
- Turbo Frame ID冲突:每个Todo条目都使用相同的
todos作为Turbo Frame的ID,导致Turbo无法精准定位单个条目进行更新/删除操作。 - Turbo Stream目标错误:创建动作中
turbo_stream.append的目标是重复的todosframe,而非包裹所有Todo的容器;删除动作中turbo_stream.remove用法错误,不需要传入partial,且目标ID不正确。 - 冗余的
remote: true参数:Rails 7的Turbo默认处理AJAX式提交,表单和删除按钮上的remote: true属于多余配置,可能干扰Turbo的正常工作。
修正后的代码
控制器代码(todos_controller.rb)
class TodosController < ApplicationController before_action :set_todo, only: [:show, :edit, :update, :destroy] def index @todos = Todo.all @todo = Todo.new end def show end def new @todo = Todo.new end def create @todo = Todo.new(todo_params) if @todo.save # 追加到包裹所有todo的容器#todos-container render turbo_stream: turbo_stream.append('todos-container', partial: 'todo_partial', locals: { todo: @todo }), notice: 'Task was successfully created.' else render :new end end def update if @todo.update(todo_params) # 替换单个todo的唯一frame render turbo_stream: turbo_stream.replace("todo-#{@todo.id}", partial: 'todo_partial', locals: { todo: @todo }), notice: 'Task was successfully updated.' else render :edit end end def edit end def destroy @todo.destroy # 删除单个todo的唯一frame,仅需传入目标ID render turbo_stream: turbo_stream.remove("todo-#{@todo.id}"), notice: 'Task was successfully deleted.' end private def set_todo @todo = Todo.find(params[:id]) end def todo_params params.require(:todo).permit(:name, :description, :status) end end
Todo Partial(_todo_partial.html.erb)
给每个Todo分配唯一的Turbo Frame ID,避免冲突:
<%= turbo_frame_tag "todo-#{todo.id}" do %> <div class="todo-item"> <h3><%= todo.name %></h3> <p>Description: <%= todo.description %></p> <p>Status: <%= todo.status %></p> <%= link_to "Edit", edit_todo_path(todo) %> <%= button_to "Delete", todo_path(todo), data: { turbo_method: :delete } %> </div> <% end %>
Index视图(index.html.erb)
添加唯一的容器#todos-container,用于接收新创建的Todo:
<h1>Index: List all todos</h1> <!-- 包裹所有todo的容器,用于Turbo Stream追加操作 --> <div id="todos-container"> <% @todos.each do |todo| %> <%= render partial: 'todo_partial', locals: { todo: todo } %> <% end %> </div> <!-- 创建Todo的表单 --> <%= render partial: 'form_partial', locals: { todo: @todo } %>
Form Partial(_form_partial.html.erb)
移除冗余的remote: true参数,添加错误提示:
<%= form_for(@todo, html: { class: 'bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4' }) do |f| %> <% if @todo.errors.any? %> <div class="alert alert-danger"> <% @todo.errors.full_messages.each do |msg| %> <p><%= msg %></p> <% end %> </div> <% end %> <div class="mb-4"> <%= f.label :name, class: 'block text-gray-700 text-sm font-bold mb-2' %> <%= f.text_field :name, class: 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline' %> </div> <div class="mb-4"> <%= f.label :description, class: 'block text-gray-700 text-sm font-bold mb-2' %> <%= f.text_area :description, class: 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline' %> </div> <div class="mb-4"> <%= f.label :status, class: 'block text-gray-700 text-sm font-bold mb-2' %> <%= f.select :status, options_for_select(Todo.statuses.keys.to_a, @todo.status), {}, class: 'shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline' %> </div> <div class="flex items-center justify-between"> <%= f.submit 'Submit', class: 'bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline' %> </div> <% end %>
Show视图(show.html.erb)
移除冗余的remote: true参数:
<h1>Show: Specific details about a certain todo</h1> <p><strong>Title:</strong> <%= @todo.name %></p> <p><strong>Description:</strong> <%= @todo.description %></p> <p><strong>Status:</strong> <%= @todo.status %></p> <%= link_to "Edit", edit_todo_path(@todo) %> <%= button_to "Delete", todo_path(@todo), data: { turbo_method: :delete } %>
内容的提问来源于stack exchange,提问作者gage
相关产品推荐
相关产品推荐

