3

I have a simple ruby on rails 7 app that uses Hotwire and turbo frames. I have a HTML table on my index page, and would like to make it with turbo frame tag, so that all the actions stay on index page.

Here is the index file:

<%= turbo_stream_from "companies" %>
<main class="container">
  <div class="header">
    <h1>Companies</h1>
    <%= link_to "Add company",
                new_company_path,
                class: "btn btn--primary",
                data: { turbo_frame: dom_id(Company.new) } 
                %>
  </div>

  <%= turbo_frame_tag Company.new %>

    <div class="table-responsive">
    <table class="table mb-0">
      <thead>
        <tr>
          <th><%= sort_link(@q, :company_name) %></th>
          <th><%= sort_link(@q, :street_address) %></th>
          <th><%= sort_link(@q, :postal_code) %></th>
          <th><%= sort_link(@q, :city) %></th>
          <th><%= sort_link(@q, :country) %></th>
          <th colspan= 2> Action</th>
        </tr>
      </thead>
      <tbody id="companies_table">
        <%= render @companies %>
      </tbody>
    </table>
    </div>

  <%= raw pagy_nav(@pagy) %>
</main>

Here is _company.html.erb partal:

<%= content_tag :tr, id: dom_id(company) do %>
  <td><%= company.company_name %></td>
  <td><%= company.street_address %></td>
  <td><%= company.postal_code %></td>
  <td><%= company.city %></td>
  <td><%= company.country %></td>
  <td>
    <%= link_to edit_company_path(company), class: "btn btn--light" do %>
        <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-pencil-square svg-icon" viewBox="0 0 16 16">
          <path d="M15.502 1.94a.5.5 0 0 1 0 .706L14.459 3.69l-2-2L13.502.646a.5.5 0 0 1 .707 0l1.293 1.293zm-1.75 2.456-2-2L4.939 9.21a.5.5 0 0 0-.121.196l-.805 2.414a.25.25 0 0 0 .316.316l2.414-.805a.5.5 0 0 0 .196-.12l6.813-6.814z"/>
          <path fill-rule="evenodd" d="M1 13.5A1.5 1.5 0 0 0 2.5 15h11a1.5 1.5 0 0 0 1.5-1.5v-6a.5.5 0 0 0-1 0v6a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5v-11a.5.5 0 0 1 .5-.5H9a.5.5 0 0 0 0-1H2.5A1.5 1.5 0 0 0 1 2.5v11z"/>
        </svg>
      <% end %>
  </td>
  <td>
      <%= button_to company_path(company), method: :delete, class: "btn btn--light" do %>
        <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" class="bi bi-trash svg-icon" viewBox="0 0 16 16">
          <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
          <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
        </svg>
      <% end %>
  </td>
<% end %>

And here is create.turbo_stream.erb file:

<%= turbo_stream.prepend "companies_table", @company %>
<%= turbo_stream.update Company.new, "" %>
<%= render_turbo_stream_flash_messages %>

Is it possible to make this table somehow dynamic, after creating a new record, to append the row to table.

thank you

PS. If I missed an important piece of puzzle, please let me know. thanks

Volkan
  • 494
  • 3
  • 14
  • 32

1 Answers1

4

I'm going to mention that this is a longstanding issue with Turbo and Tables that is still not really satisfied, as can be seen from the following issue thread on the Turbo repo. Sadly, it is still an open issue. The thread I linked to does offer some solutions. Alternatively, you can also ignore the semantically correct html and build your table using <div> elements and style them as you might style a table. Sorry that this issue continues to be troublesome, though you are not alone.

UPDATE:

I have seen an implementation that does work, though the is keyword is not currently supported in safari. See if something like this works for you:

# index.html.erb
<table class="min-w-full divide-y divide-gray-300">
  <thead class="bg-gray-50">
  <tr>
    <th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-normal text-gray-900 sm:pl-6">Name</th>
    <th scope="col" class="px-3 py-3.5 text-left text-sm font-normal text-gray-900">Email</th>
    <th scope="col" class="px-3 py-3.5 text-left text-sm font-normal text-gray-900">Date Added</th>
  </tr>
  </thead>
  <tbody class="divide-y divide-gray-200 bg-white" is="turbo-frame" id="users">
    <%= render @users %>
  </tbody>
</table>

# _user.html.erb
<tr is="turbo-frame" id="<%= dom_id(user) %>">
  <td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm">
    <div class="flex items-center">
      <div class="h-10 w-10 flex-shrink-0">
        <%= user.avatar %>
      </div>
      <div class="ml-4">
        <div class="text-gray-500"><%= user.title %></div>
      </div>
    </div>
  </td>

  <td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500"><%= user.email %></td>
  <td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500"><%= user.date %></td>
</tr>
# users_controller.rb
def create
  ...
  respond_to do |f|
    f.turbo_stream do
      flash.now[:notice] = "Created!"
      render turbo_stream: turbo_stream.after(:users, partial: "users/user", locals: { user: user },)
    end
  end
end
Bar-Levav
  • 126
  • 6