Home Does Turbo Fight with Rails Conventions?
Post
Cancel

Does Turbo Fight with Rails Conventions?

Let’s say I have a transcriptions/index.html.erb with the following code:

1
2
3
4
5
<div class="px-2 py-4">
  <ul role="list" class="divide-y divide-gray-100">
    <%= render @transcriptions %>
  </ul>
</div>

By the Rails convention, the partial transcriptions/_transcription.html.erb will get rendered for each transcription.

Let’s assume that the transcriptions/_transcription.html.erb partial has the following content:

1
2
3
<li id="<%= dom_id transcription %>">
  <!-- Actual content here -->
</li>

And also consider that we have a model called Transcription with the following the code:

1
2
3
4
5
6
7
8
class Transcription < ApplicationRecord
  after_update_commit :broadcast_updates

  private
    def broadcast_updates
      broadcast_replace
    end
end

According to the broadcast_replace documentation it’s the same as broadcast_replace_to, but the designed stream is automatically set to the current model. Here is what the broadcast_replace_to documentation says:

1
2
3
4
5
6
7
8
9
10
11
# Sends <turbo-stream action="replace" target="clearance_5"><template><div id="clearance_5">My Clearance</div></template></turbo-stream>
# to the stream named "identity:2:clearances"
clearance.broadcast_replace_to examiner.identity, :clearances

# Sends <turbo-stream action="replace" target="clearance_5"><template><div id="clearance_5">Other partial</div></template></turbo-stream>
# to the stream named "identity:2:clearances"
clearance.broadcast_replace_to examiner.identity, :clearances, partial: "clearances/other_partial", locals: { a: 1 }

# Sends <turbo-stream action="replace" method="morph" target="clearance_5"><template><div id="clearance_5">Other partial</div></template></turbo-stream>
# to the stream named "identity:2:clearances"
clearance.broadcast_replace_to examiner.identity, :clearance, attributes: { method: :morph }, partial: "clearances/other_partial", locals: { a: 1 }

This means that when my model callback gets executed, this is what will happen:

1
2
# Sends <turbo-stream action="replace" target="transcription_5"><template><li id="transcription_5">My Transcription Content</li></template></turbo-stream>
# to the stream named "transcription:5"

Considering that my index will have various transcriptions, how can I send this HTML to the index page? You need to create a stream channel for each transcription? Ok, you can add something like this to index page:

1
2
3
<% @transcriptions.each do |transcription| %>
  <%= turbo_stream_from transcription %>
<% end %>

But if you are also implementing pagination, for example, the turbo channels is one more thing that you should keep updated.

This made me feel that the implementation, or the documentation, is a bit counter-intuitive. It’s like there is a conflict between the broadcasts model methods that sets the stream automatically and the conventions long used on views.

Maybe I’m a bit addicted to using Rails conventions in a certain way, but so far I haven’t been able to see a way how these methods can represent a convention. In my head, something that you don’t need to specify parameters cover a general use case.

Anyway, for this case, the best solution I found was to use a specific channel name with turbo_stream_from in transcriptions/index.html.erb:

1
2
3
4
5
6
7
<%= turbo_stream_from :transcriptions %>

<div class="px-2 py-4">
  <ul role="list" class="divide-y divide-gray-100">
    <%= render @transcriptions %>
  </ul>
</div>

And use broadcast_replace_to in Transcription model:

1
2
3
4
5
6
7
8
class Transcription < ApplicationRecord
  after_update_commit :broadcast_updates

  private
    def broadcast_updates
      broadcast_replace_to :transcriptions
    end
end

I’m only starting my journey of using Turbo Stream on a real application, so if you think I’m overlooking something, let me know!

This post is licensed under CC BY 4.0 by the author.

Configuring TailwindCSS Prettier Plugin for ERB Files in VS Code

-