Authentication and Devise with broadcasts

You cannot do that. You should pass in a prop instead. Partials should be “pure”. See what DHH said:

Not having global references in broadcasts make sense. However, I wish there was more official guidance on how to handle this. Consider a very simple and common case of a Chat app which has rooms. In each room is a list of users currently in the room that updates with Turbo Streams. If I want to have special handling for the current user’s entry in the list of users (such as to add permissioned links or even just adding “(you)” suffix), this becomes extraordinarily complex.

Currently, I have the basic functionality working with RoomsChannel and users are added to a Redis-backed list of users for that channel and I turbostream the full list whenever someone subscribes or unsubscribes. How can I ensure a “(you)” label on my name in the list of users? Or, let’s say I want to not show my name in the list because it will be shown at the top and the list of users in the room is a list of “everyone else”. How can this be accomplished?

In my understanding broadcast_append_to renders the html once. So, every subscriber receives identical html, it cannot be tailored for every subscription.

As a workaround, I broadcast the following html:

== turbo_frame_tag message, src: message_path(message)

It adds an extra request, but keep the code simple.

The other option is a dedicated channel, and do the rendering there.

1 Like

Am I understanding correctly that you’re streaming back a turbo frame tag which just then fetches the information like a normal HTTP request? That actually seems really elegant and simple.

2 Likes

Am I understanding correctly that you’re streaming back a turbo frame tag which just then fetches the information like a normal HTTP request? That actually seems really elegant and simple.

yes you got it right

1 Like

There’s a hack to hande current_user from the broadcast. Check the logic in this video behind display_controls partial’s local.

@gaultierq The turbo_frame solution sounds like a good way to go.
But I have a couple questions to try to understand this:

I get why this would be true broadcasting from a model.
But is this also true when broadcasting from the controller?

Would this be a channel identified by both the message and the user?

@RCA Thanks for proposing broadcasting from the controller. I’m doing that however, and my current_user is always evaluating to the user making the update. It’s broadcasting the same HTML to everyone regardless if they should have edit privileges, so everyone gets the edit links on update.

Are you saying you have a way to do this that renders appropriate HTML per subscriber?

You can broadcast from the model or the controller, both will end up calling ActionCable.server.broadcast. The html will be rendered by the ApplicationRenderer and broadcasted subscribers. The same html will be send to every subscribers to a specific channel. If you call it from the controller you will be able to pass current_user as a param to the renderer, that’s the only difference I think.

What I meant is User 32 can either subscribe discussion 28 by subscribing to a dedicated channel discussion28_user32 and receive a custom html.

1 Like

Merci gaultierq, this is the bit that’s been hard to grasp. When people say “you can pass current_user from the controller” (I have read this in many places), they don’t mention the HTML is going to be broadcast to everyone as if the current_user is the user doing the create/update — that’s the person initiating the controller request. That means everybody will get the edit/delete controls, which is never what’s desired.

This is not well stated in the Turbo broadcast docs, and I wouldn’t say it’s clear from dhh’s post above either. There are so many questions on SO about it. Here it is for anyone who arrives at this thread:

We simply cannot broadcast user-specific HTML to a websocket channel that is not also user-specific, in Rails or anywhere else. We need either to broadcast a turbo-frame with src that will cause the client to make a call to the path to get a fresh partial, or we need to show/hide the controls with our CSS.

1 Like

well said ! you nailed it :slight_smile:

One more question: If you broadcast from the controller (not the model), and someone creates/updates/deletes via the API, will it be broadcast? Update (I just tested it…) No it will not.

This must be the (unexplained!) reason why it’s suggested to broadcast from the model… should be mentioned in any discussion of broadcasting from the controller, I think