ruby-on-railsviewturbolinks

Ruby on Rails link_to renders multiple times


I have an index page that shows multiple shipment cards. I want to wrap each of these shipments in a link_to that will visit the show page of the shipment. For some reason, when I inspect the HTML in my browser dev tools I can see that the link_to renders multiple times and the tags that gets generated does not surround the card as expected. What am I doing wrong?

Here is my code:

<%= 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 %>

An example of the 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>

I have another index page with the exact same layout and the link renders as expected (one tag surrounding the card). This is why I am expecting my code above for my shipments index page to work exactly the same, but I can't figure out why it does not.

Here is the code for the index page with the link_to that works as expected:

<%= render Atoms::PageLayoutComponent.new(header: "Find a rule/regulation") do |page_layout| %>
  <% page_layout.with_page_content do %>
    <%= render Ui::ShipmentRules::ShipmentRulesFiltersComponent.new(shipment_rules: @shipment_rules) %>
    <%= turbo_frame_tag "reseller_shipment_rules_results" do %>
      <div class="grid gap-3">
        <div>Recently updated rules</div>
        <% @shipment_rules.each do |shipment_rule| %>
          <%= link_to reseller_shipment_rule_path(shipment_rule), data: { turbo_frame: "_top" } do %>
            <%= render Ui::ShipmentRules::ShipmentRuleComponent.new(shipment_rule:) %>
          <% end %>
        <% end %>
      </div>
    <% end %>
    <div class="grid place-content-center">
      <%== pagy_nav(@pagy) %>
    </div>
  <% end %>
<% end %>

Solution

  • I realised what caused the strange behaviour. I have a nested <a> tag in the child component (ShipmentComponent) which is actually forbidden. Nesting <a> elements is not valid HTML, so the browser was trying to "correct" the code.