ruby-on-railshotwire-railshotwire

Hotwire/Turbo Frames: why `target: "_top"` isn't requesting pages via fetch?


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?


Solution

  • Found the solution.

    Instead of

    <%= link_to user.name, user, target: :_top %>
    

    One should use

    <%= link_to user.name, user, data: { turbo_frame: :_top } %>