Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Dynamically re-use & lazy-load page using Hotwire
Avo profile imageAdrian Marin ⛵️
Adrian Marin ⛵️ forAvo

Posted on

     

Dynamically re-use & lazy-load page using Hotwire

This article was originally published onavo.cool

Hotwire is a fantastic technology that helps you build dynamic websites without thinking about JavaScript.

When we re-wrote Avo from VueJS to Hotwire, when it first came out, we had to think about how we could leverage it to our advantage.

One of the first things we did was to add dynamic turbo-frames around common pages.

For example, theResourceIndex page is the page that usually displays the table with the requested resources (it shows the users on/users).
We knew that we could use that exact partial when we wanted to display thehas_many association on theResourceShow page but didn't know how at first. We could have extracted it to a partial and rendered it in theResourceShow page underneath the record details, but theResourceShow page would take a long time to load when you have many associations to one record.

We then came up with the idea to use a turbo-frame for that but still didn't want to use a partial.

Let's say we haveUser andTeam models like so:

classTeam<ApplicationRecordhas_many:usersendclassUser<ApplicationRecordbelongs_to:teamend
Enter fullscreen modeExit fullscreen mode

The routes and controllers look like this:

resources:postsget"/:resource_name/:id/:related_name/",to:"associations#index"
Enter fullscreen modeExit fullscreen mode
classBaseController<ApplicationControllerdefindex# if there's a query set up, use it, if not, set one upunlessdefined?@query@query=@resource.class.query_scopeendendendclassAssociationsController<BaseControllerdefindex# find the parent record and set the query@query=@parent_model.public_send(params[:related_name])endend
Enter fullscreen modeExit fullscreen mode

So what happens there? When a user goes to/users, they will see the list of users, and if they go to/teams/TEAM_ID/users, they should see the same list of users but scoped to the respective team.

In order to achieve this usingturbo-frames we'll add a lazy-loaded turbo frame on theRecordShow page with thesrc attribute set to the association path with the?turbo_frame="has_many_users" param added to the path/teams/TEAM_ID/users?turbo_frame="has_many_users" url.

<!-- views/base/show.html.erb --><!-- record details here --><!-- association details below --><turbo-frameid="has_many_users"src="/teams/#{@team.id}/users?turbo_frame=has_many_users"target="_top"><!-- Loading state --></turbo-frame>
Enter fullscreen modeExit fullscreen mode

Next, we should add a dynamic wrap around theindex.html.erb partial like so.

<!-- views/base/index.html.erb --><%ifparams[:turbo_frame].present?%><turbo-frameid="<%=params[:turbo_frame]%>"><%end%><!-- The list of records --><%ifparams[:turbo_frame].present?%></turbo-frame><%end%>
Enter fullscreen modeExit fullscreen mode

What happens is that when the user loads a teamsShow page/teams/1, that page will display with the lazy-loaded frame (so no impact on the performance of that page on load), which in turn, loads the associationIndex page with theturbo_frame param. That will add the<turbo-frame> tag around the template allowing Turbo to replace the content dynamically on the page.

We're re-using the actualindex.html.erb template and theBaseController#index action.

Of course, this can be improved using some helpers and a partial.

# app/helpers/application_helper.rbdefturbo_frame_wrap(name,&block)renderlayout:"partials/turbo_frame_wrap",locals:{name:name}docapture(&block)endend
Enter fullscreen modeExit fullscreen mode
<!-- app/views/partials/turbo_frame_wrap.html.erb --><%ifname.present?%><turbo-frameid="<%=name%>"><%end%><%=yield%><%ifname.present?%></turbo-frame><%end%>
Enter fullscreen modeExit fullscreen mode
<!-- views/base/show.html.erb --><!-- record details here --><!-- association details below --><turbo-frameid="<%=turbo_frame%>"src="<%=frame_url%>"target="_top"><!-- Loading state --></turbo-frame>
Enter fullscreen modeExit fullscreen mode
<!-- views/base/index.html.erb --><%=turbo_frame_wrap(params[:turbo_frame])do%><!-- The list of records --><%end%>
Enter fullscreen modeExit fullscreen mode

You can do the same thing forShow pages too. We did with Avo.

You can find a more detailed example on Avo's GitHub repo.

Stay cool and improve performance 💪

avo.cool/
avo.cool/repo
avo.cool/feedback
avo.cool/try

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Trending onDEV CommunityHot

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp