Search code examples
ruby-on-railsactioncable

helper_method not working with ActionCable


I am new to Ruby on Rails and I have been trying to understand ActionCable for the past 2 months.

I have a helper method :current_user defined in

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  helper_method :current_user

  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end

end

When calling it from

app/views/layouts/application.html.erb

<%= current_user.id %>

it displays: 1 for example. However, when I bring :current_user to Action Cable, it displays empty or nil.

app/channels/application_cable/connection.rb

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user
      logger.add_tags "ActionCable", "User: #{current_user.id}"
    end

  end
end

Terminal: Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket) There was an exception - NoMethodError(undefined method `id' for nil:NilClass)

Thanks in advance for any help or direction.


Solution

  • If you see the doc you provided, you will know that identified_by is not a method for a Channel instance. It is a method for Actioncable::Connection. From Rails guide for Actioncable Overview, this is how a Connection class looks like:

    #app/channels/application_cable/connection.rb

    module 
     ApplicationCable class Connection < ActionCable::Connection::Base
     identified_by :current_user
    
      def connect 
          self.current_user = find_verified_user 
      end 
    
      private
      def find_verified_user 
       if current_user = User.find_by(id: cookies.signed[:user_id])
           current_user 
       else
           reject_unauthorized_connection 
       end 
      end
     end 
    end
    

    As you can see, current_user is not available here. Instead, you have to create a current_user here in connection. The websocket server doesn't have a session, but it can read the same cookies as the main app. So I guess, you need to save cookie after authentication. Thanks ASAP..