Ruby on Rails | Hotwire | RubyUI - How to solve performance issues when expanding a form details within a list of forms
The final result is highly practical, reactive, performant, and functional.
Consider a scenario where you have a list of forms, as illustrated in the image below.
And for each completed form, you can view the details in a side modal, without needing to navigate to the form's detail page.
Considering that a user may have multiple forms, and each form needs to load several questions and answers from the database to display the final result, it’s crucial that we avoid running a single, heavy query that loads a massive amount of HTML—most of which the user likely won’t even see.
The solution to this problem is quite simple and straightforward.
We need to open the side modal at the moment the user clicks the preview button, send a request to Rails with the selected document’s ID, and use TURBO_STREAM to update the content of the side modal.
Let’s implement the solution.
The first step is to define the route and the controller behavior triggered by the user’s click.
Recommended by LinkedIn
# config/routes.rb
resources :documents, only: %i[index show], shallow: true do
get :preview_sheet
end
# buyers/documents_controller.rb
def preview_sheet
@document = Document.find(params[:document_id])
authorize!(@document, to: :show?, with: ::Ssr::DocumentPolicy)
end
# buyers/documents/preview_sheet.turbo_stream.erb
<%= turbo_stream.update("PREVIEW_SHEET") do %>
<%= render(Buyers::Documents::PreviewSheet::Information.new(document: @document)) %>
<% end %>
The second step is to display the side modal with a generic loading indicator—or, in this case, I implemented a skeleton loader, as it provides a more modern and visually appealing experience.
The RubyUI code below is responsible for opening the side modal, but there are a few important points to clarify before diving into the code itself.
First, it's necessary to add data_turbo_stream="true" to the HTML element, as we won’t be updating the entire page with the request—only the content of the side modal.
Second, we need to assign an id to the div that will be updated via TURBO_STREAM. In this case, I used 'PREVIEW_SHEET'.
# buyers/documents/preview_sheet.rb
Sheet do
SheetTrigger do
href = buyers_document_preview_sheet_path(@form_group)
Link(href:, variant: "ghost", class: "p-1 size-fit", data: {turbo_stream: true}) do
lucide_icon("eye", class: "size-4 flex-none text-primary")
end
end
SheetContent(class: "w-full max-w-xl") do
div(id: "PREVIEW_SHEET") do
10.times do
div(class: "my-4 w-full h-8 animate-pulse rounded-md bg-muted")
end
end
end
end
The third step is to populate the document data in the side modal.
# buyers/documents/preview_sheet/information.rb
SheetHeader do
href = edit_buyers_form_groups_override_path(@document)
div(class: "mt-6 flex flex-row items-center justify-between gap-3") do
SheetTitle { @document.display_name }
Link(href:, variant: "outline") { "Edit" }
end
end
SheetMiddle do
# ... SHEET CONTENT HERE ...
end
Thanks a lot for reading it!