Open jonsgreen opened 3 years ago
In case someone else bumps into this here is one of probably many solutions to deal with this problem if you are using CableReady
first you need multiple identifiers for your connection to deal with unauthenticated users:
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
identified_by :session_id
def connect
self.current_user = env["warden"].user(:user)
self.session_id = request.session.id
reject_unauthorized_connection unless self.current_user || self.session_id
end
end
end
then you will want a SessionChannel for when users are not yet authenticated:
class SessionChannel < ApplicationCable::Channel
def subscribed
stream_for session_id
end
end
import CableReady from 'cable_ready'
import consumer from './consumer'
consumer.subscriptions.create('SessionChannel', {
received (data) {
if (data.cableReady) CableReady.perform(data.operations)
},
connected () {
document.addEventListener('reconnect', this.reconnect)
},
reconnect() {
consumer.disconnect()
consumer.connect()
}
})
Then finally in your session_controller:
class Users::SessionsController < Devise::SessionsController
# POST /resource/sign_in
def create
super do
cable_ready[SessionChannel].dispatch_event(name: 'reconnect')
.broadcast_to(request.session.id)
end
end
end
I am sure there are ways to do this with just Turbo and Stimulus but perhaps this can be an inspiration.
So I recognize that there are other issues similar or related to this one like https://github.com/hotwired/turbo/issues/45 and if this has been covered elsewhere I apologize.
I am noticing that if I have a channel identified by current_user then if I submit a Turbo enabled authentication form (e.g. with Devise) then I don't have access to the current user through the ActionCable channel. A full refresh of the page establishes connection immediately. This behavior is also fixed by adding a turbo-false data element to the form. A final option that sort of works is to do something like this (note that this is with an ApplicationCable::Connection identified by both session id and current_user):
The problem with this last solution is that it takes several seconds for ActionCable to detect the stale connection which can lead to confusing UX for the user. The initial connection on page load is quite snappy in comparison.
My conclusion is that when Turbo handles the redirect the connection to ActionCable does not get refreshed.
Maybe just disabling turbo in the form is good enough but I am curious if there is a way and whether it would make sense for Turbo to trigger ActionCable to reconnect in such cases.