in misc

Turbo Frame Reload Error: “element has a source URL which references itself”

I love Marco's turbo_power library for adding some extra actions to turbo. For example the turbo_frame_reload which should reload a given turbo frame.

But the turbo_frame_reload didn't work in my situation.

I've got an index view which renders all orders in a turbo-frame (with pagination).
Pressing a button next to an order should tag the order and reload the orders page.
Tagging is an action in other controller, which doesn't know anything about this order screen. But after tagging it should refresh the turbo frame with the orders.

I thought this could be easy by refreshing the turbo_frame with a turbo_stream action turbo_frame_reload. This only works if the frame has a src attribute in it.

When I set src on the this frame I get the error: element has a source URL which references itself. So this isn't working.

Workaround I created for now is the following.

I add an extra turbo_stream action named: turbo_frame_reload_with_data. This sets the source on the attribute data-src when the src attribute is empty/missing. (that's on the initial load).

So define the turboframe like this:

<%= turbo_frame_tag :orders, data_src: request.original_url do %>
.. content .. 
<% end %>

To make this work the following code is added to the application.js, adding a custom turbo-stream action.
This action sets the src of the turbo-frame when a turbo_frame_reload_with_data action is invoked

Turbo.StreamActions.turbo_frame_reload_with_data = function() {
  this.targetElements.forEach((element) => {
    let src = element.getAttribute('src') || element.getAttribute('data-src')
    element.src = ''
    element.src = src

Note: Always setting src with data-src doesn't work. The data-src isn't updated on turbo-frame updates, only the src-flag is.

To make the rails experience nicer, a helper is added to the turbo_stream tag builder.

module TurboStreamActionsHelper
  def turbo_frame_reload_with_data(target = nil, **attributes)
  custom_action :turbo_frame_reload_with_data, target:, attributes:

In the controller performing the action, I render the following turbo-stream action. To refresh after this, the following can be returend.

render turbo_stream: turbo_stream.turbo_frame_reload_with_data('orders'),