Hotwire Turbo does not replace turbo-frame, throws warning: Response has no matching <turbo-frame id=...> element
Asked Answered
D

2

17

I'm getting started with Hotwire and Turbo in Rails 6 and have an issue with Turbo not replacing my turbo-frame. I'm receiving the following error message: Response has no matching <turbo-frame id="experiments"> element.

I have the following being rendered on the page from a controller action:

<!-- index.html.erb -->
<turbo-frame id="experiments" src="/labs/experiments">
  <p>This message will be replaced by the response from /labs/experiments.</p>
</turbo-frame>

This correctly sends the request to /labs/experiments, and when I check my network requests the following is returned from my controller:

<h2>Experiment 1</h2>
<h2>Experiment 2</h2>

However, the response is not rendered inside my turbo-frame and instead I receive a console log warning: Response has no matching <turbo-frame id="experiments"> element.

Any help is appreciated :)

Declaratory answered 25/10, 2021 at 17:50 Comment(0)
D
16

Okay I figured out what was happening.

TL;DR

The response to the turbo-frames request must contain the same id as the turbo-frame that sent it. Since the turbo-frame in index.html.erb contains an id of 'experiments':

<!-- response from /labs/experiments wrapped in turbo-frame with id -->
<turbo-frame id="experiments"> 
  <h2>Experiment 1</h2>
  <h2>Experiment 2</h2>
</turbo-frame>

This entirely fixed the error I was receiving, and turbo started populating the turbo-frame with the results from the server.

Full Example with erb

Since I haven't been able to find too many full examples yet, here is my simple example of using turbo-frames (which are awesome!). Note that the routes, controller methods (etc) are intentionally over simplified, but helped greatly in my understanding:

Routes

get 'examples' => 'examples#index'
get 'examples/experiments' => 'examples#experiments'

Controller

class ExamplesController < ApplicationController
  # renders some simple html, including a turbo-frame
  def index; end

  # renders the content of the turbo-frame
  def experiments
    @experiments = [
      { name: 'React Keyboarding Environment', url: '/keyboarding' },
      { name: 'Accessible Keyboarding', url: '/accessible' }
    ]
    render partial: 'experiments'
  end
end

Views

app/views/examples/index.html.erb

<h1>Examples#index</h1>

<turbo-frame id="experiments" src="/examples/experiments">
  <p>This message will be replaced by the response from /experiments.</p>
</turbo-frame>

app/views/examples/_experiments.html.erb

<%= turbo_frame_tag :experiments do %> 
  <% @experiments.each do |experiment| %>
  <h2><%= experiment[:name] %></h2>
  <% end %> 
<% end %>
Declaratory answered 25/10, 2021 at 18:16 Comment(0)
H
0

In our case, the problem was the authorization configuration in the app/controllers/turbo_frames_controller.rb.

We had this code

class TurboFramesController < ApplicationController
  skip_authorization_check # <= we are using the CanCanCan gem

  def show
    authorize! :manage, current_admin # <= this line was blocking calls for guest users.
    render partial: params[:partial]
  end
end

Adding if current_admin at the end of that line solved our issue.

Heliotrope answered 5/6 at 10:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.