Skip to main content

Group Chat with ActionCable: Part 5 Discussion

General • Asked by Chris Oliver

Hi Chris,
How many users is a chatroom-site like this able to handle?

thanks,

That will depend on how big your server is and it's configuration. I haven't tested any websocket stuff at scale, but I've seen some performance tests for 10,000 users before. It starts to slow down at a point, and they were using simulated things, so never real world data. Your mileage will probably vary quite heavily if you start going past a couple thousand users.

Hi Chris,

Do you mean 10,000 simultaneous users of the chat, or just having 10,000 users on the site itself?

-Monroe

10k ActionCable connections.


Hey Chris,
With this code (no controller action and message creation happens in channel), what is the best way to authenticate the user for message creation? The only solution that comes into my mind is front-end authentication with currentUserId on the body tag and checking with jQuery if there is any number, I don't really like it. Is there a better approach at the moment?

What we setup earlier was Devise so that you can login and since WebSockets share the same cookies a web request does, when you connect to the WS, it will log you in with Warden (devise's underlying authentication layer) and let you use the WebSocket. Then we have access to the current_user method inside ActionCable just like we do in a normal web request.

On the frontend, you can add a current-user meta tag keep track of it in your JS so that you can customize your frontend to handle things differently if you're not logged in, etc. Check out this episode for more on that: https://gorails.com/episode...


Hi Chris,
Awesome tutorials!!!

I followed instructions to refactor the existing code from last episode, but it doesn't work on my end. When I type in the message and press Enter, it doesn't get sent, nothing happens. I tried to log the message, but also nothing... I am not sure what happened there... Did you have similar problems?

Thank you!
Marko


Hi Chris. You're a life saver with these tutorials!

How would you extend this app to be or allow one-to-one chat. I've been thinking of a channel being created for each user-user combination - and only show it to those users. Conceptually it doesn't sound as an elegant solution to me. How would you go about it? or if you could point me in the right direction.

Thank you,
Alex

The main thing is probably that you could create a "direct_message" attribute for Channel where you can mark it as a direct message and auto-attach the users (yourself and the person you want to DM). On create, you can attach the users to it, and then pretty much everything else probably works about the same. The navbar probably renders direct message ones separate from the main channels and should only display for users who are in it.

When you say channel do you mean Chatroom or Chatroom_users? Or something else? I'm a newbie to programming so I'm still getting used to the language and how to understand technical explanations :)

Ha, no worries at all. :)

You'll need to tweak or at least work on both a bit. Basically you want to create a private Chatroom where the only two ChatroomUser records are you and the person you want to talk to.

Thank you! I got a working version of it by creating two ChatroomUsers on the Chatroom create function. but when I integrated on my multi-tenant app, everything works except the realtime part of it. I believe it has something to do with the MessageRelayJob part - is says "Performing MessageRelayJob from Async(default)" That should be redis though, right?


Hi Chris, thanks for these very good explanations. You mentioned the possibility of disconnecting a user from a channel when he wants to leave.
I don't know if it is explained in one of the two next pro episodes and if not I have two questions :)
I've used your tutorial to build a simple realtime messaging app with Mailboxer. It works pretty well thanks to you. What would be the simplest way to disconnect a user from a channel ? I would call the stop_all_stream function but I don't know exactly how to.
Furthermore, by calling this function, do we disconnect a user from a single chatroom or from all the chatrooms ?
Thanks a lot !

Interestingly, there isn't a stop_stream method in ActionCable, so you'd have to stop all streams at least right now. Someone has opened a PR with this but it's still pending: https://github.com/rails/ra...

For now, I guess you can either stop_all_streams and reconnect to the ones you want, or you can monkey patch in the code from that pull request. I would probably do that because it's likely to get accepted.

And to implement the disconnect, you'd just send the message from the JS to call a method in the server side channel to call the stop stream. This would look almost exactly like sending a message, you'd just pass in the name of the channel you want to remove.

Thank you for this answer and your dedication !


Hi Chris. Thanks for your great tutorial!!

I want to keep the chatroom name bold. But if I reload the page, the chatroom name back to normal font-weight...
How can I keep that css??

Thank you,
K


Hi, chris. Thank you for taking me so far.
But i got a problem. you remember this

  $("#new_message").on "submit", (e) ->
    e.preventDefault()

but in my case, the 'e.preventDefauly()" does not work always. sometimes, it goes html like

Started POST "/chatrooms/1/messages"

And sometimes, it goes from coffees to job&channel... like

Started GET "/cable/" [WebSocket] for 127.0.0.1

Do you see any clear answer this problem? Help me:)
And why e.preventDefault() and following coffee codes do not work sometimes?
As i see log, when socket successfully connencted it works fine. But if there is no "Socket successful..." sentence, then it goes HTML way....why?!! :(

Hi Chris, I am hoping you can help me narrow down my error. I am trying to set up the app on a multi-tenancy app. I had all the models working before we started to use Action Cable, Active Job, and the more complex coffee script. I was able to add messages to the chatroom without any errors. But, now I am getting an error message where the tenant_id is NULL. I have tried to figure out where and how I would add the tenant_id to the code. Where do I add the tenant_id? Do I need to add it to the coffee script or the channel or the job? Or would I need to add it to multiple locations? 

please help me! 
i build a message app in my web following this tutorial.
but As i enter the chatroom & send message, then 

"ActionController::InvalidAuthenticityToken in MessagesController#create" error occurs.
I think it means "submit" acts as html form.

but As i enter the chatroom & refresh, then log tells me that 

"Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)" 
it means actioncable is working now.

so, user has to refresh as they enter the chatroom. it is rediculous, right?
what is the reason? Why actioncable does not work when entering the chatroom at the first place?

Hi Chris,

I really appreciate your tuts. It help to open my mind with action cable.
I am new to rails action cable. I wander if action can work in this case.
The channel only broadcast to client who subcribed for the channel with the stream.
How can it behaves like when I send a message to other user. The room just get created so I didn't reload or refresh to stream for that room. So how can I tranmmit the message to the receiver?

Thanks.


@chris, I just finished video #5 of the Chatrooms tutorial. Everything looks ok in terminal output, but when I hit 'enter' key after typing a message I still have to refresh browser to see the message appear. Here is repo: https://github.com/rmindigo/chat_demo_gorails Any ideas why message doesn't appear instantly? Terminal output below. Thanks!

[ActionCable] [User 12] Finished "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-29 16:51:10 -0800
[ActionCable] [User 12] ChatroomsChannel stopped streaming from chatrooms:3
Started GET "/cable" for 127.0.0.1 at 2019-01-29 16:51:10 -0800
Started GET "/cable/" [WebSocket] for 127.0.0.1 at 2019-01-29 16:51:10 -0800
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 12], ["LIMIT", 1]]
[ActionCable] [User 12] Registered connection (Z2lkOi8vY2hhdC9Vc2VyLzEy)
[ActionCable] [User 12] Chatroom Load (0.3ms) SELECT "chatrooms".* FROM "chatrooms" INNER JOIN "chatroom_users" ON "chatrooms"."id" = "chatroom_users"."chatroom_id" WHERE "chatroom_users"."user_id" = ? [["user_id", 12]]
[ActionCable] [User 12] ChatroomsChannel is transmitting the subscription confirmation
[ActionCable] [User 12] ChatroomsChannel is streaming from chatrooms:3
[ActionCable] [User 12] ChatroomsChannel#send_message({"chatroom_id"=>3, "body"=>"see my message"})
[ActionCable] [User 12] Chatroom Load (0.3ms) SELECT "chatrooms".* FROM "chatrooms" WHERE "chatrooms"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
[ActionCable] [User 12] (0.1ms) begin transaction
[ActionCable] [User 12] SQL (0.8ms) INSERT INTO "messages" ("chatroom_id", "user_id", "body", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["chatroom_id", 3], ["user_id", 12], ["body", "see my message"], ["created_at", "2019-01-30 00:51:22.264530"], ["updated_at", "2019-01-30 00:51:22.264530"]]
[ActionCable] [User 12] (28.0ms) commit transaction
Message Load (0.4ms) SELECT "messages".* FROM "messages" WHERE "messages"."id" = ? LIMIT ? [["id", 49], ["LIMIT", 1]]
[ActionCable] [User 12] [ActiveJob] Enqueued MessageRelayJob (Job ID: b63d1b75-902b-47c9-b864-d6aec9495db6) to Async(default) with arguments: #<GlobalID:0x007f90e113e998 @uri=#<URI::GID gid://chat/Message/49>>
[ActiveJob] [MessageRelayJob] [b63d1b75-902b-47c9-b864-d6aec9495db6] Performing MessageRelayJob (Job ID: b63d1b75-902b-47c9-b864-d6aec9495db6) from Async(default) with arguments: #<GlobalID:0x007f90e1137f08 @uri=#<URI::GID gid://chat/Message/49>>
[ActiveJob] [MessageRelayJob] [b63d1b75-902b-47c9-b864-d6aec9495db6] Chatroom Load (0.2ms) SELECT "chatrooms".* FROM "chatrooms" WHERE "chatrooms"."id" = ? LIMIT ? [["id", 3], ["LIMIT", 1]]
[ActiveJob] [MessageRelayJob] [b63d1b75-902b-47c9-b864-d6aec9495db6] User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 12], ["LIMIT", 1]]
[ActiveJob] [MessageRelayJob] [b63d1b75-902b-47c9-b864-d6aec9495db6] [ActionCable] Broadcasting to chatrooms:3: {:username=>"bratPitt", :body=>"see my message", :chatroom_id=>3}
[ActiveJob] [MessageRelayJob] [b63d1b75-902b-47c9-b864-d6aec9495db6] Performed MessageRelayJob (Job ID: b63d1b75-902b-47c9-b864-d6aec9495db6) from Async(default) in 3.17ms
[ActionCable] [User 12] ChatroomsChannel transmitting {"username"=>"bratPitt", "body"=>"see my message", "chatroom_id"=>3} (via streamed from chatrooms:3)


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 24,647+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.