Piotr Jaworski
Technologies

Rails Chat Application – part 1 [tutorial]

   Back to list

Have you ever dreamed about creating your own chat application that works like Facebook Messenger? In this tutorial, we will use the Rails 5 feature called ActionCable to build one without using any front-end framework (expect jQuery – but it’s just a light library). Our goal is to create a real time Rails chat application that sends and shows messages to a recipient instantly without any page refresh.

The final application will look like:

rails-chat-application-screenshot-1

This tutorial is split into two parts. In the first part, we will cover and describe the basics of our application without using ActionCable, including how to start a new conversation and send a basic message. In the second part, we will add real time messages and new message notifications. The tutorial is split to provide detailed information about the Rails 5 new feature – ActionCable, and to better describe how our application works and what every single line of the application does.

Basic setup

Make sure that you have Rails 5.0.0 installed. To check that you do, run:

If you don’t have the latest version, download it from RubyGems.org running:

If you are done with the Rails 5 setup, please create a new application project. We will use SQLite as a database provider.

Now let’s create a separate gemset for our application. To do so, run:

Then quit from the directory and re-enter to create a new gemset and to install bundler:

Adding devise and seeds

Let’s add a devise to our Gemfile. The file should look like this (I don’t use coffee-script and other gems):

Then run the following commands:

Add the authenticate_user! filter to the ApplicationController:

Create our home page controller and updates routes.rb file:

Replace the application.js and the layouts/application.html.erb files with (we won’t use turbolinks):

Replace the seed.rb file and fill it with our database:

Adding bootstrap

As in every tutorial, we will use Twitter Bootstrap in our CSS. Let’s add it:

Add to the Gemfile:

Bundle it:

Rename application.css to application.scss and replace it with:

We won’t use Bootstrap JS features, so we aren’t adding it to our application.

Adding application models

Our application will have three models (we’ve added one already):

  • User
  • Conversation
  • Message

It’s everything that we will need. One conversation has a recipient and a sender – two users. A message has a sender – a user that belongs to a conversation. Of course, one user will have many messages and conversations.

Let’s add code for this schema and models:

Update generated file and add an unique index:

Now we need to connect everything together. Add to the User class:

Also we need to edit a bit our conversation model:

We have two users in the model, so we need to recognize each by adding a custom attributes to the belongs_to method.

We also added uniqueness validation. Remember that we also validate it with index in the database, so even without Rails validation, we can’t add a duplicated record too. It’s awesome!

The opposed_user methods returns an opposed user to the requested user. We will need it later.

Adding first views

If you haven’t already noticed, Facebook supports an awesome chat feature. If you open a chat window once, and close a page or a tab in a browser, it’s still active and appearing on the page when you come back to it later. It looks like this:

rails-chat-application-screenshot-2

How could we add this same feature to our chat application? Simple! We’ll keep in a session array with conversation_ids which we opened. While we close a window, we’ll remove a conversation_id from the array.

First, update the index method in the HomeController:

We’re also including other models under the @conversations query to avoid N+1 queries.
Under the @users query, we select all users that are not us. They’ll be displayed on the chat list.

Let’s add views. Replace the home/index.html.erb file with:

Add the conversations/_converastion.html.erb file:

Add the conversations/_conversation_content.html.erb:

Add the messages/_message.html.erb file:

Add styles to the application.scss file:

What have we just added? Please refresh the page and check.

rails-chat-application-screenshot-3

For now, the left part of the page is empty for displayed conversations. On the right, there is a user list that contains all users. We will now be able to start a conversation with any of them!

Starting a conversation

We have everything prepared for starting a new conversation, now let’s add some code!

Start by  adding our new resource to the routes.rb file:

Update the conversation.rb file:

We added the between scope. It returns a conversation between two requested users. The get method is also a new code. It tries to get a conversation between two users – and if it’s present, it returns it. If there isn’t any, it creates a new one.

Add the ConversationsController:

In the create method, we just get a conversation between a current user and requested user. If in the session there is no added conversation_id yet, we’ll add it, if not, we’ll just respond with a js file.

Update in the home.index.html 18th line, from:

To:

Now, create the conversations/create.js.erb file:

What are we doing here? First of all, we try to find an existing conversation window in the ‘#conversations-list’ div. If it doesn’t exist (length !== 1), we add to the ‘#conversations-list’ div a new conversation. If we add it, we need to reassign to the conversation variable added element. Later, we call the show() method to display a conversation’s window.

Finally, we check the height of the window and scroll to the bottom of it. If we send a new message, we should always be at the bottom of a conversation.

The application home page should look like (it depends how many windows you have opened):

rails-chat-application-screenshot-4

Closing and minimizing a conversation

What happens if we open a conversation by a mistake? We can’t close it or even minimize yet. Let’s add these features!

Update the routes.rb file:

Replace the 5th line in the _converastion.html.erb file with:

Add the close method to the Conversations controller:

It removes the requested converastion_id from the session and closes a window on the front-end.

Add the close.js.erb file:

This one line finds requested div and removes it from the body tag.

Add method which is responsible for minimizing a window:

It runs a jQuery toggle() method and scrolls to the bottom of the window if it’s visible.

Now you should be able to open, close, and minimize a conversation window!

Sending a message

Now for the most important feature, sending a new message! It will be very simple, we just need to create a new record and append it to a conversation’s window.

Let’s edit the routes.rb file:

Add the form to the _converastion.html.erb file after the ‘.message-list’ div.

Add the MessagesController:

The create method creates a new message object and responds with the js file.

Create the create.js.erb file inside the messages directory:

This JavaScript code finds the requested conversation window and appends a partial with a new message.

Add styles to the application.scss file to set a max height of a window:

Now we can test our new feature! It should look like:

rails-chat-application-screenshot-5

Conclusion

In a few steps, we created a fully working chat application without touching any front-end framework. It’s not real time chat yet, but in the next part of the application we will cover ActionCable and use it to build awesome features!

I hope that you liked this tutorial and you can subscribe to our newsletter for additional information about the next!

Whole code could be found here.

  • bryn mrk

    Nice tutorial! 👍🏽 it!