Broadcasting (or transmitting?) user-specific information

I have an application where a lot of processing happens in Jobs. I tried out Turbo Streams to notify subscribers about updates, e.g. with a model Post, the subscribers would subscribe to turbo_stream_from dom_id(post) to receive updates, and the background job would trigger post.broadcast_replace(_later)_to dom_id(self). So far so good, works like a charm, and was an easy way to add Websockets functionality :100:

Now comes the catch, what happens if the application will get localized, say to english and german. Background jobs are enqueued with the current locale, so either en or de. Now, when the call to post.broadcast... happens, the corresponding partial will be rendered in german. But if some user is subscribed and is viewing the english version of the site, he will suddenly receive an update in german :exploding_head:

For now, I solved this by using turbo_stream_from("#{dom_id(post)}_#{I18n.locale}"), which will open different channels like post_123_de and post_123_en. When broadcasting the update, I do

I18n.available_locales.each do |locale|
   I18n.with_locale(locale) do
    broadcast_replace_later_to "#{dom_id(self)}_#{locale}"
  end
end

That works so far, however, it does not really scale. What if the logged in user can choose his timezone, and I need to format a date accordingly? What if the partial shows different amount of informations based on the current user (authorization)? And what if a user is looking at the index view of posts, but is only allowed to view specific posts? I would need to skip updates for that specific user when using broadcast_append_to.

Now I see that this defeats the purpose of a broadcast, which is just sending out information like a radio station. I feel that we might need a possibility to say “Get every user that is subscribed to this stream name, and render the partial for him”. I’ve done similar with graphql-ruby and subscriptons, where there are both possibilities, called triggers and broadcasts.

Any plans or ideas on that topic? Thanks in advance :hugs:

2 Likes

Hello, we are currently having exactly the same issue.

Did you find a pattern that solves this issue?

Hi, for times I recommend you to use local_time.

basecamp/local_time: Rails engine for cache-friendly, client-side local time (github.com)

We have the same issue too. Any update on making turbo to broadcast things in the correct language and in a scaleable way?

You can make Turbo locale-aware with just a few patches (sorry, I don’t have an actual code at hand, only slides):

(From: [RailsConf 2022] The pitfalls of realtime-ification - Speaker Deck)

Yes, you still broadcast N times (by the number of locales). It may be ok if you have a handful of locales supported. Otherwise… Well, you need to look for other options (also mentioned in the talk linked above).