viktor-shmigol / ng2-cable

Connect your Angular(2/4)/ionic(2/3) application with Rails ActionCable
https://ng2-cable-example.herokuapp.com
44 stars 14 forks source link

Send parameter when subscribe to channel #13

Closed chrisbenseler closed 7 years ago

chrisbenseler commented 7 years ago

To subscribe to a channel, there is this example: this.ng2cable.subscribe('http://example.com/cable', 'ChatChannel');

but, what if is needed to send a parameter to the channel? In the Rails docs, it is possible with:

App.cable.subscriptions.create { channel: "ChatChannel", room: "Best Room" }

viktor-shmigol commented 7 years ago

@chrisbenseler Thanks for letting me know about that. I'll try to implement it.

chrisbenseler commented 7 years ago

@viktor-shmigol there is another problem: when user does this

this.ng2cable.subscribe('http://example.com/cable', 'ChatChannel', { room: 'My room' });

he should be able to listen for events on ChatChannel only for 'room: My room' when he uses something like this

this.ng2cable.subscribe('http://example.com/cable', 'ChatChannel', { room: 'My room' }); this.ng2cable.subscribe('http://example.com/cable', 'ChatChannel', { room: 'My room2' });

this.broadcaster.on('ChatChannel') will receive 2 times the response message. I guess the the .on() method from broadcaster objeto should also receive the param, not?

rafayet-monon commented 6 years ago

I am making a subcription line this -

this.ng2cable.subscribe('http://demo.lvh.me:3000/cable', 'NotificationsChannel', {'current_user': '1'});

I cannot get the current user in connect method of connection.rb using request.params[:current_user] What am I doing wrong? @chrisbenseler @viktor-shmigol

viktor-shmigol commented 6 years ago

@rafayet-monon As far as I understand that you would like to identify user's connection. In my opinion there is no sense to pass:

{'current_user': '1'}

If you are using "Token-based authentication" you need to pass token to backend:

this.ng2cable.subscribe('http://example.com/cable?token=1234', 'ChatChannel')

and update app/channels/application_cable/connection.rb:

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

    def connect
      check
      self.current_user = user
    end

    protected

    def check
      reject_unauthorized_connection unless user
    end

    def user
      User.find_by(token: request.params[:token])
    end
  end
end

or get token from cookies:

app/channels/application_cable/connection.rb:
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      check
      self.current_user = user
    end

    protected

    def check
      reject_unauthorized_connection unless user
    end

    def user
      User.find_by(id: verifier.verify(cookies[:token]))
    rescue ActiveSupport::MessageVerifier::InvalidSignature
      nil
    end

    def verifier
      ActiveSupport::MessageVerifier.new(ENV['secret_key_base'])
    end
  end
end

After that you can call method 'current_user' in you channel. E.g:

class ChatChannel < ApplicationCable::Channel
  def subscribed
    current_user.update_columns(online: true, seen_at: Time.now)
    stream_from "chat_#{current_user.id}"
  end

  def unsubscribed
    current_user.update_columns(online: false, seen_at: Time.now)
  end
end