Search code examples
ruby-on-railswebsocketactioncable

multiple users chat receiving on action-cable


I have created one project where I have one customer and another contractor. I implemented ruby on rails actioncable for chat. All it is going good but issue is coming when two different people chat with one person, that person is receiving both messages in socket window. I realised that I have setup conversation-#{user_id} as a channel, so user is listening on this channel now two people send chat to him, they both will come on same channel. How can I avoid this? or can I add another user in channel string, but I found it is very difficult. Any idea where I have to send params to subscribe method.

connection

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

    def connect
      self.current_user = find_session_user
    end

    def find_session_user
      current_user = User.find_by(id: cookies.signed[:actioncable_user_id])
      current_user || reject_unauthorized_connection
    end
end

My conversation channel

class ConversationChannel < ApplicationCable::Channel
  def subscribed
    stream_from "conversations-#{current_user.id}"
  end

  def unsubscribed
    stop_all_streams
  end

  def speak(data)
    message_params = data["message"].each_with_object({}) do |el, hash|
      hash[el.values.first] = el.values.last
    end
  end

    ActionCable.server.broadcast(
      "conversations-#{current_user.id}",
      message: message_params,
    )
end

This code is just condense version, but as it will start conversation-user_id as a channel, so definitely when it is connected and other people send message, this user will receive them in same socket. so I have to do like `conversation-user_id-anotehr_user. Right now it is working on web/mobile and all good, but when two user communicate with one user it create issue by displaying two users chat on one socket.

Any idea how can I create such channel.


Solution

  • I have solved this issue by binding chat with 2 persons and I have another requirement of job specific chats, so have bound it with it too. Now my conversation channel is like conversation-(talk_id)-(listern_id)-job_id so it all good now. Following are changes I did 1. I removed channel file from assets/javascript as it is automatically load on my application, but I want to bound it with few parameters so I added it to specific view. My controller has already few parameters so I have changed this javascript to following

    <script>
    App.conversation = App.cable.subscriptions.create({channel: "ConversationChannel",
        job_id: <%= @job.id %>, 
        contractor: <%= @contractor %>
      }, {
      connected: function() {},
      disconnected: function() {},
    
      received: function(data) {
        var conversation = $('#conversations-list').find("[data-conversation-id='" + data['conversation_id'] + "']");
        conversation.find('.messages-list').find('ul').append(data['message']);
    
        var messages_list = conversation.find('.messages-list');
        var height = messages_list[0].scrollHeight;
        messages_list.scrollTop(height);
      },
    
      speak: function(message) {
        return this.perform('speak', {
          message: message
        });
      }
      });
    

    Now when connection establish it sends both parameters and channel channel properly individual. On my conversation.rb I have just minor change

      def subscribed
        stream_from "conversations-#{current_user.id}-#{params[:contractor]}-#{params[:job_id]}"
      end
    

    Now everything working perfectly as per our requirements, each channel is being made with 2 users+job Id so I they can communicate on specific job and with specific users, so there no more other person can listen other conversation. Just posting may help someone.