Я использую ActionCable для предоставления уведомления браузера, которое легко реализовать. Проблема возникает, когда пользователь открыл несколько вкладок в браузере, и мне нужно отправить данные только на одну вкладку, то есть только на один WebSocket в пользовательской комнате. Как это может быть сделано?





Изоляция одного клиента публикации/подписки невозможна напрямую с подходом публикации/подписки, потому что вся идея заключается в том, что издатели ничего не знают о подписчиках.
Тем не менее, есть два распространенных способа решить эту проблему:
использовать другой именованный канал для каждого соединения, сохраняя именованный канал в базе данных и пересылая все сообщения на этот конкретный именованный канал (т. е. сохраняя канал user-ID-TIMESTAMP в базе данных и используя его в качестве целевого соединения).
другой, несколько более надежный подход (хотя и более сложный) состоит в том, чтобы послать сообщение всем клиентам, но создать условие гонки, которое позволяет только одному клиенту получить реальное сообщение. Это будет выглядеть примерно так:
Удачи!
Каждый раз, когда устанавливается новое соединение, мы создаем новую комнату. Так, например, когда пользователь устанавливает новое соединение, мы можем указать имя комнаты как users:user_id:some_unique_random_string, которое может быть равно пользователям:user_id:123j123b1h2b1j23bh12b3, и когда тот же пользователь устанавливает другое соединение, открыв другую вкладку, мы также сделаем то же самое и создать отдельную комнату. Теперь одна вещь, которую предоставляет ActionCable, заключается в том, что мы можем найти все названия комнат, за которыми следует любой префикс.
Допустим, пользователь сделал три подключения и его комнаты являются пользователями: 128: 123n1jh123ko9876, пользователями: 128: asdas23412cs1234, пользователями: 128: asni9202h5i3jens, тогда мы также можем получить имя этой комнаты с помощью ActionCable.
user_id = 128
pubsub = ActionCable.server.pubsub
channel_with_prefix = pubsub.send(:channel_with_prefix, RoomChannel.channel_name)
channels = pubsub.send(:redis_connection).pubsub('channels', "#{channel_with_prefix}:users:#{user_id}:*")
Теперь каналы представляют собой массив, состоящий из названий комнат.
Итак puts channels
["chatapp_production:users:128:123n1jh123ko9876", "chatapp_production:users:128:asdas23412cs1234", "users:128:asni9202h5i3jens"]
Вот как мы можем найти все комнаты, относящиеся к одному пользователю, без использования каких-либо внешних баз данных и вызовов API.