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

迁移至Rails7的应用中Turbo Frame/Stream首次提交后失效求助

问题:Hotwire集成后仅首次提交有效,后续提交停滞

我正在将Hotwire集成到一个从Rails 6.1迁移至Rails 7的项目中,希望提交下拉框新值后用新版本表格替换原有表格,但目前仅首次提交正常,后续无法提交,陷入停滞状态。


相关代码

表格局部视图(documents/_edit_tag_table.html.erb)

<%= turbo_frame_tag "new_tag_#{tag_name}_#{issuer}" do %>
    <table class="table table-bordered" id="edit_table">
        <thead>
        <tr>
            <th scope="col">Tag</th>
            <th scope="col">Acciones</th>
        </tr>
        </thead>
        <%= render partial: "document_tags/document_tag", locals: {document: document, tag_name: tag_name, issuer: issuer} %>
    </table>
<% end %>

标签局部视图(document_tags/_document_tag.html.erb)

<tbody id="tags-table-body">
    <% document.document_tags.each do |document_tag| %>
        <% if document_tag.tag&.tag_type&.name == tag_name %>
            <tr>
                <td><%= document_tag.tag.name %></td>
                <td>
                    <%= button_to document_tag_path(document_tag, return_to: @redirect_url), 
                        method: :delete, 
                        data: { confirm: '¿Estás seguro que deseas eliminarlo?' }, 
                        class:"btn btn-outline-danger", 
                        remote: true do %>
                        <i class="fas fa-trash-alt"></i>
                    <% end %>
                </td>
            </tr>
        <% end %>
    <% end %>
    <tr> 
        <% document_tag = DocumentTag.new %>
        <%= form_with(model: document_tag, local: true, data: { turbo_stream: true }) do |form|%>
            <% if document_tag.errors.any? %>
                <div id="error_explanation">
                <h2><%= pluralize(document_tag.errors.count, "error") %> prohibited this document_tag from being saved:</h2>
                    <ul>
                    <% document_tag.errors.full_messages.each do |message| %>
                        <li><%= message %></li>
                    <% end %>
                    </ul>
                </div>
            <% end %>
            <td>
                <% tag_type = TagType.find_by(name: tag_name) %>
                <% if tag_type %>
                    <%= form.hidden_field :document_id, value: document.id %>
                    <%= form.hidden_field :tag_type, value: tag_name %>
                    <% if @redirect_url %>
                        <%= form.hidden_field :return_to, value: @redirect_url %>
                    <% end %>
                    <%= form.collection_select(:tag_id, 
                        Tag.where(tag_type_id: tag_type.id), 
                        :id, :name, 
                        {:prompt=>true}, 
                        {class: 'form-control js-example-basic-single', id: tag_type.id, onchange: "this.form.requestSubmit()"}) %>
                <% end %>
            <td>
            <%= form.submit "Agregar tag", class: 'btn btn-primary' %>
            </td>
        <% end %>
    </tr>
</tbody>

控制器代码(document_tags_controller.rb)

def create
  respond_to do |format|
    if @document_tag.save
      format.turbo_stream do
        render turbo_stream: turbo_stream.replace(
          "new_tag_#{@document_tag.tag.tag_type.name}_false", 
          partial: "documents/edit_tag_table", 
          locals: {
            document: @document_tag.document, 
            tag_name: @document_tag.tag.tag_type.name, 
            issuer: false 
          }
        )
      end
      format.html { redirect_to edit_document_path(@document_tag.document), notice: 'Se ha añadido el tag exitosamente.' }
      format.json { render :show, status: :created, location: @document_tag.document }
    else
      format.html { render :new }
      format.json { render json: @document_tag.errors, status: :unprocessable_entity }
    end
  end
end

问题原因及修复方案

1. 事件绑定丢失(核心问题)

你用内联onchange: "this.form.requestSubmit()"绑定下拉框提交事件,但Turbo替换DOM后,新渲染的元素不会自动继承原有事件绑定,导致后续下拉框选择后无法触发提交。

修复:
使用Turbo内置的data-turbo-submit-on-change属性替代内联事件:

<%= form.collection_select(
  :tag_id, 
  Tag.where(tag_type_id: tag_type.id), 
  :id, :name, 
  {prompt: true}, 
  {
    class: 'form-control js-example-basic-single', 
    id: "tag_id_#{document.id}_#{tag_type.id}", # 新增唯一ID避免冲突
    data: { turbo_submit_on_change: true }
  }
) %>

2. Turbo Frame ID不匹配

控制器中硬编码了issuer: false,但初始渲染的Turbo Frame ID是new_tag_#{tag_name}_#{issuer},如果初始issuer不是false,替换后的Frame ID会和原ID不一致,导致后续Turbo操作失效。

修复:

  • 在表单中添加issuer隐藏字段,传递初始值:
    <%# 在document_tags/_document_tag.html.erb的form内添加 %>
    <%= form.hidden_field :issuer, value: issuer %>
    
  • 在控制器中使用提交的issuer参数保持ID一致:
    # 控制器create方法中修改
    render turbo_stream: turbo_stream.replace(
      "new_tag_#{@document_tag.tag.tag_type.name}_#{params[:document_tag][:issuer]}", 
      partial: "documents/edit_tag_table", 
      locals: {
        document: @document_tag.document, 
        tag_name: @document_tag.tag.tag_type.name, 
        issuer: params[:document_tag][:issuer]
      }
    )
    
  • 确保document_tag_params允许issuer参数。

3. 表单Turbo设置冲突

Rails 7中form_with默认使用Turbo驱动,你同时设置local: true和data: { turbo_stream: true }会导致Turbo无法正确处理后续请求。

修复:
移除local: true,保留data: { turbo_stream: true }:

<%= form_with(model: document_tag, data: { turbo_stream: true }) do |form|%>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:57:32