Not all web apps need chat, but if you want to communicate with your customers, or you want them to communicate with each other, you’re going to run into this problem quickly. CometChat Pro is a fantastic alternative to rolling your own chat service. You’ll see that you can easily insert chat into your application, without it getting in the way of other content you may be delivering.
This tutorial doesn’t assume much knowledge at all. Ruby on Rails is an incredibly easy framework to get started with. If you’ve worked with other web technologies, you’ll probably find it very clear and very opinionated.
I assume you are able to run Rails applications - which means you already have Ruby and bundler installed. This application uses Ruby 2.5.3 and Rails 5.2.2 but nothing happening here is special for latest versions - you could plug these tools into any modern version of Rails.
One of the hardest parts of building chat is dealing with concurrency - users need to see new messages without refreshing their browsers. CometChat Pro achieves this with very little code, as you will see.
If you’ve ever tried to use Action Cable to achieve similar results, you will be very pleased with how quickly you can copy-paste your way to real-time updates in the browser.
Grab yourself a terminal and fire up a new Rails app: rails new cometchatpro --skip-active-record -T. We don’t need a database for this, and the -T prevents Rails from creating test files for us. If you’ve already got an application, you can skip this step - it should be easy to pop this code into an existing project.
Environmental variables and CometChat credentails
Next, you’re going to need an API key and an App ID from CometChat Pro. Once you’ve logged in, head to the dashboard and create a new app.
Hold your horses ⚠️🐴!
To follow this tutorial or run the example source code you'll need to create a V1 application.
v2 will be out of beta soon at which point we will update this tutorial.
After that, generate an API key. You’ll need fullAccess, not just authOnly. Grab those credentials and add them to your .env file. You’ll need your file to look something like this:
Next, add dotenv-rails to your Gemfile and bundle. Now your application can read your environmental variables. These are private credentials for your CometChat Pro account; do not commit this file to your version control!
Next we’ll add some boilerplate Rails views and routing so we can chat as a user with other users. Generate a new controller: rails generate controller Users. This will create a number of files, which we’ll get into shortly. You’ll also need to add a route to your new view in config/routes.rb. Here’s what my routes.rb looks like:
If you jump into the GitHub code or pop over to the hosted app, you’ll see that I have added user creation. I’ve left it in place because I already built it, but CometChat Pro comes with sample users baked into every account, so you can start testing right away without needing to set up user creation first. I’ve omitted discussion of user creation for this tutorial in the sake of brevity, but you can see the code needed for that in the Github repo.
You’ll also need to create a /views/users/show.html.erb file. We’ll fill it will content in a moment.
Let’s get into the meat of our application - interacting with the CometChat API. I organized interactions with CometChat Pro into a service. Here’s what it looks like:
CometChat Pro does a lot of things, and as we grow our app, we might want to fill this service with further interactions with their API. Here, all we need to do is fetch a list of users we can chat with. Note that no gem is needed to interact with CCP, you simply send your requests however you like (I used HTTParty) with the proper headers (from our .env file) and CCP sends back the information you requested.
I map the JSON response from CCP into the information my application needs - the user name and the user ID.
Working with the service in the users controller
Now that we have a protocol established for speaking with the CCP API, we can use it in our UsersController. Here’s what mine looks like:
I’ve skipped over the index page for brevity, but it’s just a list of users who we may “chat as”. You can think of it as the most insecure, ridiculous login page imaginable. On both views, we fetch the users registered with our CometChat Pro app. We’ve already mapped the JSON response in the service, so on the index and show pages we loop through users to display them. On the show page, we are chatting “as” a user, so we don’t want him to show up in the list of possible people to chat with (line 9).
The user show view
Who is talking?
To make information about our “logged-in” user (the one whose show page we are on) available to the CometChat service, we’ll want to include an invisible div with the user name and id. You can put this anywhere on your page:
The user list
To display the list of users as shown above, here’s the erb code:
There’s nothing special happening here - the only thing to note is that we are setting the user id as an id on the list-item. We’ll need it later to reference which user we are speaking to. Remember that our @users has come from the controller, where we gathered the list of users from the CometChat service.
Receiving and displaying messages
Next, let’s look at how we will display incoming messages. Our code starts as this:
We need to supply a div for CometChat Pro to load messages into. I’ve called mine messages but you could call yours anything you like.
We’ll use Ruby’s form helpers to create our message form, but we don’t let Ruby handle any of the functionality here:
We’ll need to take the following steps:
1. Initialization - set up a connection to the CometChat service.
2. Log in a current user.
3. Select a user to chat with and fetch message history with that person.
4. Add an event listener to pick up new messages from the other person.
5. Set up an action to send messages.
First, we’ll need to get our app talking to the CometChat Pro service and log in. In application.html.erb, add this line between the <head> tags:
Add these lines to the bottom of /views/users/show.html.erb:
After initialization, we need to log in the current user. This application includes no security whatsoever - anyone can chat as anyone else. Obviously you’d want to have something just a tiny bit more customized in a production app. Here’s how we log in our user on CometChat Pro:
Remember that weird tag('div') that held our user information from show.html.erb? Here we use it to find out what user needs to log in. If something has gone wrong with that div, we just bail from this operation.
Next, we call our next CometChat method: .login. We take the id we got from the user div, and use our API credentials. If CometChat Pro sends back a User, we update the message div to say “Choose a user to start chatting”.
Let’s hop back to the show.html.erb page where we called setUserListeners() at the bottom of the view. In order to know who we want to chat with, we’ll need to listen for clicks on the user list. Here’s what that code looks like:
userDivs is a node list of divs, one for each of the users we can chat with. We loop through them and add event listeners on each. If we click on a user, we want to first call setUser to tell our application who we want to talk to, and then fetchMessages for that user.
setUser and addMessageListener
Here’s where we really get some magic and CometChat Pro takes care of the heavy lifting for us. Once we log our user in and select someone to chat with, we want to see any new messages from that person in real time. With CometChat Pro, we don’t have to worry about keeping any websockets open or dealing with refreshing - the messages just appear as you would expect.
The setUser function is only concerned with making the active user blue in the list, so I’ve skipped it here. But it also calls the addMessageListener class, which is critical for receiving new messages as they come in:
This is taken almost directly from the CometChat Pro documentation. We call the CometChat addMessageListener method, then using incoming messages to update our message div. Fire up two different browsers to see this in action (or just check out the gif above).
When that new message comes in, we’ll need to update our view. Here’s the code:
First, if the incoming message isn’t between our logged-in user and the user we’re chatting with, we ignore it. Then, we need to process the new message - we construct a new div with the message, then we append it to the messages div, again scrolling to the bottom so we can see it.
Our newMessage method will simply format the message - it’s a new bubble in our chat app. We check if the sender has the same id as the logged-in user so we can apply the self class to the div - making it pink for “self” and blue for everybody else.
Before we start chatting, we need to see the messages that have come before and anything that was exchanged when we weren’t chatting with that particular user. Our fetchMessages method will grab the messages between our logged-in user and our selected user.
If for some reason we don’t have an id, we’ll return so as not to get errors. First we construct our request, setting the ID of the user we want to talk to, and the limit of messages we want to receive. More complicated applications would want to automatically fetch results from further back in time as the user scrolls.
Once our message requester is set up, we can call fetchPrevious to grab a list of messages. This returns messages, which we can use to populate our messages div. Each message is a JSON object with a sender.uid, sender.name and a text. We map through the messages and return them as HTML objects and replace whatever is inside messages with our new message node list. Remember to .join('') them or you’ll see a bunch of commas between divs. If there were no messages, we want to show the user that this is the “start of message history”.
Last, we want to scroll to the bottom of the messages div to show the user the latest messages.
Sending new messages
We’re logging in, selecting a user to chat with, fetching all the old message history between these two, and receiving any new messages sent to us from that user. Finally, we want to be able to send messages. Here’s how we do it:
First, we determine which user we are chatting with, based on the highlighted user in the list. Next, we read the message from the form, and clear the form so it’s ready for the next message.
Our textMessage object will call CCP’s TextMessage method, constructing a message to send based on the logged-in user, receiver id, message text, and the types of message and recipient. Then we just sendMessage with our textMessage object, wait for a message response, and render the message in the same way we would an incoming message from another user.
And that, my friends, is everything we need to install chat in our Rails app!
Best of luck installing chat in your own app and have fun!