Turbo.setFormMode("optin"), links with data-turbo="true" do not send turbo request

Does Turbo.setFormMode("optin") disable turbo requests in links?

I’m updating a mature app using Rails 6.1, recently added gem turbo-rails 1.5.0, gem importmap-rails 1.2.3 to start converting forms to Hotwire.

# app/javascript/application.js
import "@hotwired/turbo-rails"
Turbo.setFormMode("optin")

In a translation page erb template, I have links that should GET a turbo-stream request for a tiny edit form. The response should update a separate turbo-frame (or a div, have tried both), elsewhere on the page, replacing it with the edit form.

link_to(label, edit_translation_path(id: t_tag, locale: @lang.locale),
        data: { turbo: true, turbo_frame: "translation_ui",
                tag: t_tag, role: "show_tag" })

The issue is that these links are not sending request.format turbo-stream, they’re sending request.format text/html - I can see this in the log output, and confirm it if I break in the controller action.

Things I have tried:

  • modifying the link path edit_translation_path(format: "turbo-stream")
  • modifying the route format in config/routes.rb get(:edit, to: "translations#edit", as: "edit_translation", defaults: { format: :turbo_stream })
  • adding Turbo.session.drive = true to app/javascript/application.js
  • changing data: { turbo: true } to data: { turbo_method: :get }

Documentation on the whole Turbo “optin” workflow, which I imagine affects most people with existing, mature Rails apps, needs to be improved. The answer is buried in Turbo Reference: Attributes, thankfully linked in Alex’s answer to my StackOverflow question:

GET links and GET forms need to have data-turbo-stream attribute to send a TURBO_STREAM request:

<%= link_to "GET link", "/", data: {turbo_stream: true} %>

<%= form_with url: "/", method: :get, data: {turbo_stream: true} do |f| %>
  <%= f.submit "GET form" %>
<% end %>

Note that data: {turbo_stream: true} is deceptively similar to, and different from, the data: {turbo: true} attribute that you’d use on a form with any method other than GET.

IMO this was far too difficult to find and wasted a lot of my time, when optin could simply be better documented - I’m going to try an issue in the turbo-rails gem.