Ruby on Rails中link_to重复渲染问题排查求助
修复link_to重复渲染无法完整包裹货运卡片的问题
问题回顾
我做了一个展示货运卡片的索引页,想用link_to把每个卡片整个包起来,点击跳转到对应货运的详情页。但浏览器开发者工具里查看HTML时,发现link_to重复渲染,生成的<a>标签根本没包住整个卡片,反而拆成了多个零散的<a>。
问题代码
<%= render Atoms::PageLayoutComponent.new(header: "Orders") do |page_layout| %> <% page_layout.with_header_slot do %> <%= render Ui::Shipment::ShipmentFiltersComponent.new(shipments: @shipments) %> <% end %> <% page_layout.with_page_content do %> <%= turbo_frame_tag "reseller_shipments_results" do %> <div class="grid gap-3"> <% @shipments.each do |shipment| %> <div class="grid grid-cols-1 gap-0.5 lg:grid-cols-[75%_25%] lg:gap-2"> <%= link_to reseller_shipment_path(shipment.shipment_reference), data: { turbo_frame: "_top" } do %> <%= render Ui::ShipmentComponent.new(shipment:) %> <% end %> <%= render Ui::InvoiceTogglesComponent.new(shipment:) %> </div> <% end %> </div> <% end %> <div class="grid place-content-center"> <%== pagy_nav(@pagy) %> </div> <% end %> <% end %>
生成的异常HTML
<div class="grid grid-cols-1 gap-0.5 lg:grid-cols-[75%_25%] lg:gap-2"> <a data-turbo-frame="_top" href="/reseller/shipments/123"> </a> <div class="rounded bg-white p-3 shadow hover:shadow-lg transition-all duration-200"> <a data-turbo-frame="_top" href="/reseller/shipments/123"> </a> <div class="grid gap-2 text-neutral-300 text-xs"> <a data-turbo-frame="_top" href="/reseller/shipments/123"> <div class="flex justify-between"> <div class="flex gap-2 flex-wrap items-center"> <div class="text-neutral-500 font-semibold"> xxxx </div> <div> xxxx </div> </div> </div> </a> </div> </div> </div>
原因分析
对比正常工作的索引页代码,核心差异在于组件内部逻辑:
- 正常页面的
Ui::ShipmentRules::ShipmentRuleComponent内部没有渲染额外的link_to标签,外层link_to能完整包裹组件内容。 - 出问题的
Ui::ShipmentComponent内部自己也渲染了link_to标签,而HTML规范不允许<a>标签嵌套。浏览器检测到无效嵌套后,会自动拆分外层<a>标签,提前闭合并在内部<a>前后重新生成,最终导致重复<a>的现象。
解决方案
方案一:修改组件移除内部link_to
直接修改Ui::ShipmentComponent的代码,删掉组件内部所有link_to逻辑,让外层link_to统一负责包裹和跳转。这样浏览器就能正常渲染单个<a>标签包裹整个卡片。
方案二:用点击事件替代外层link_to(无需修改组件)
如果无法修改组件,或者需要保留组件内部跳转逻辑,可以把外层link_to换成JavaScript点击事件:
<div class="grid grid-cols-1 gap-0.5 lg:grid-cols-[75%_25%] lg:gap-2"> <!-- 用div包裹卡片,绑定点击跳转事件 --> <div onclick="Turbo.visit('<%= reseller_shipment_path(shipment.shipment_reference) %>')" data-turbo-frame="_top" style="cursor: pointer;" > <%= render Ui::ShipmentComponent.new(shipment:) %> </div> <%= render Ui::InvoiceTogglesComponent.new(shipment:) %> </div>
这种方式避免了<a>嵌套问题,同时保留了Turbo的跳转逻辑。
内容的提问来源于stack exchange,提问作者UrGirlLumi
相关产品推荐
相关产品推荐

