How to render two partials for a broadcasted object on to two different pages?

Hi everyone!

Relatively new to Stimulus and Hotwire and wanted to know,

"Is there a way to render two different partials for the same broadcasted object on two different pages?

I’m trying to render and broadcast an object on a page from one controller to another page from different controller with different styling.

Example
If I print <%= render @live_room.room.questions %> in page live_room.html.erb
and print <%= render @room.questions %> in show.html.erb

They both render the partial _question.html.erb

I would like render a different design depending on the page.

Has anyone faced this issue before or know how to solve this? I’d love to get some insight!

Cheers!
A

1 Like

Yeah so if you just pass through the object, you’ll get the same partial back. Because you’ve just passed a model, Rails has to assume you want the model partial. Rails only knows what the partial is calling a method (to_partial_path) on your model. By default, that returns something like questions/question, which is how your _question.html.erb partial is working.

But that’s just shorthand. You can simply tell Rails what partial you want: <%= render "questions/whatever", question: some_way_to_access_the_question %>.

It looks like you have a collection, though. So there’s another permutation: <%= render collection: @live_room.room.questions, partial: "questions/whatever" %>. That will render the questions/whatever partial for each question. But one point of caution: the name of the question variable that’s exposed to you in the partial is, by default the name of the partial. So in my example, it’d be whatever and you’d do whatever.created_at, or something. That can be awkward so you can customise the name of the variable by sending an as parameter, like so: <%= render collection: @live_room.room.questions, partial: "questions/whatever", as: :question %>. Now you can do question.created_at and so on.

This is more of a Rails question than a Hotwire / Stimulus question. You can check out the Rails docs on all things rendering here.

When it comes to broadcasting with Hotwire, the broadcasts methods (broadcasts_replace_to and friends) accept some of the same options you can pass to render. They take a partial argument. So your broadcasting, extending the example above, may look something like: broadcasts_append_to :quesions, partial: "questions/whaetever".

3 Likes

Thanks Dan! The partial rendering work.

The only think I can’t seem to get my head around is how to turbo_stream the content on to a 2 second page “live_room/show”.

Whenever I’ve added the example you gave to the Question Model broadcasts_append_to :questions, partial: "questions/whatever"

It streams the partial to the original broadcasted “room/show” page.

I’m trying to broadcast to both room/show and live_room/show page as attempted in the below Model. I’m not sure when I’m going wrong.

Can Hotwire broadcast to two view?

class Question < ApplicationRecord
	belongs_to :room
  	broadcasts_to :room

  	after_create_commit -> { broadcast_append_to live_room, partial: "questions/live_question" }
  	after_destroy_commit -> { broadcast_append_to live_room, partial: "questions/live_question" }
  	after_update_commit -> { broadcast__append_to live_room, partial: "questions/live_question" }

  	validates :content, presence: true
end

Warm regards!
A

Presumably, on rooms/show, you have a turbo_stream_from @room call? I think you just need to copy that to live_rooms/show. Turbo will broadcast to wherever you’re streaming from.

Yup I have turbo_stream_from @room called. Even tried passing through turbo_stream_from @live_room.room. No luck

It’s hard to say what the problem is there without being able to see your app. But Turbo should stream to anywhere where you stream from the same live_room you’ve set up in your broadcast callbacks. It doesn’t matter you have two different pages streaming the same thing.

Hey Dan,

Is there a way to stop Hotwire from rendering the id="questions" from questions/question with to_partial_path ?

When broadcasting the render collection: code you shared, the object gets broadcasted from questions/question and only show’s the partial questions/whatever once the page has been refreshed, or if the questions/whatever is already on the page.

Figured it out.

#Question model

broadcasts_to ->(question) { :rooms }
after_create_commit ->(question) { broadcast_append_to :live_rooms, partial: "questions/whatever" }
after_update_commit ->(question) { broadcast_replace_to :live_rooms, partial: "questions/whatever }
after_destroy_commit ->(question) { broadcast_remove_to :live_rooms }

#live_room show view
<%= turbo_stream_from :live_rooms %>

code…

#room show view
<%= turbo_stream_from :rooms %>

code…

1 Like

@AnthonyFrancis I have proposed a change to the Turbo Rails gem to allow for passing of partial so you can do something like this

broadcasts_to ->(question) { :rooms }
broadcasts_to ->(question) { :live_rooms }, partial: "questions/whatever"

It is little less code and conveys the message more clearly that we want to render a different partial for same model on different channels.

Here is the PR if you want to review and comment to help get it merged Allow rendering to be passed so that we can change the partial and object when broadcasting by ankurp · Pull Request #113 · hotwired/turbo-rails · GitHub

3 Likes