I'm in the early stages of migrating a Rails app from Turbolinks/rails-ujs (using good ol js.erb
views that worked wonders) to Hotwire/Turbo.
Picture a traditional users/index.html.erb
page with a search form and results table:
<%= form_with(scope: :search, url: url_for, method: :get, data: { turbo_frame: "users_table" }) do |f| %>
<%= f.search_field :name %>
<% end %>
<%= turbo_frame_tag("users_table") do %>
<% @users.each do |user| %>
<%= link_to user.name, user, target: :_top %>
<% end %>
<%== pagy_bootstrap_nav(@pagy) %>
<% end %>
So, the search form above can update the turbo_frame_tag below without a full page reload (which keeps the focus and the state in the form, as desired).
Each link inside the turbo_frame_tag is expected to navigate to /users/show, replacing the entire page. And it works, due to the inclusion of the target: :_top
attribute in each link.
However, the user experience is suffering. With Turbolinks, each link inside the users_table issued a AJAX navigation, replaching the 'body' and felt very, very snappy. With Turbo/Hotwire, I can see in devtools that only the pagination (inside the turbo frame) and form submission (due to the turbo_frame attribute) are being fetched using fetch
, while the link in the user name is being requested as a regular document
navigation.
It gets worse: the back button also doesn't have any cache, so clicking in an user name and coming back takes 5 times more than it took with Turbolinks.
Is this an expected regression when using Turbo? Anytime I have a link inside a turbo_frame that I want to break out of the frame I'm losing all the benefits of the ajax navigation?
Found the solution.
Instead of
<%= link_to user.name, user, target: :_top %>
One should use
<%= link_to user.name, user, data: { turbo_frame: :_top } %>