Skip to content

Drive is including Accept: text/vnd.turbo-stream.html on visits that are not inside of a Frame #139

@agrobbin

Description

@agrobbin

We are working on transitioning a JS-heavy filtered list to Turbo Frames + Streams, and something we've run into seems like it might be a bug in Turbo.

We have a DealsController#index action that is one of the primary parts of our application, with a link in our main navigation to it like this:

<a href="/deals">Deals</a>

We've got Turbo Drive set up for the application, so with no introduction of Frames/Streams, this works perfectly, it updates the <body> through Drive as expected. Then we started introducing <turbo-frame>s to support things like infinite scrolling of "deals", with our index.html.erb looking something like this:

<%= turbo_frame_tag 'deals', target: '_top' do %>
  <%= render @deals %>
<% end %>

<%= turbo_frame_tag 'deals-next-page', src: url_for(page: @page + 1), loading: 'lazy' %>

And an index.turbo_stream.erb that looks something like this:

<%= turbo_stream.append 'deals' do %>
  <%= render partial: @deals, formats: %i[html] %>
<% end %>

<%= turbo_stream.replace 'deals-next-page' do %>
  <%= turbo_frame_tag 'deals-next-page', src: url_for(page: @page + 1), loading: 'lazy' %>
<% end %>

However, when we introduce index.turbo_stream.erb, our navigation link (which is outside of any <turbo-frame> and should behave just as a simple Drive request) no longer works as expected. Instead of getting the full HTML response from the server and replacing the <body>, it receives index.turbo_stream.erb, which makes for all sorts of weird issues when clicking that navigation link from other pages (i.e. from our home page, where there is no <turbo-frame id: 'deals'> element on the page).

After looking into this a bit more, I'm pretty sure it's because Turbo Drive is including the Accept: text/vnd.turbo-stream.html header with all of its requests, which is causing my controller to respond with that format if it's available.

When clicking a link (or submitting a form) inside of a <turbo-frame> (without a target='_top'), that makes perfect sense to me, but I'm surprised it does this when clicking a link anywhere else on the page. In that case, I'd expect Turbo Drive to do its thing, and simply fetch the standard HTML response from the server, without the text/vnd.turbo-stream.html content type included in the Accept header.

Am I misunderstanding something basic about Turbo, or is this something that should be fixed?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions