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:


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:


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/_conversation.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.


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:


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):


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:



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!

  • Joel Garcia

    Omg! The best tutorial i have seen to build a chat in rails 5. i Expect very excited the second part

    • Piotr Jaworski

      Thank you @disqus_BuDT8EjEFd:disqus !

  • Pingback: Rails Real Time Chat Application similar to Messenger - part 1 [tutorial]()

  • Domitrius Clark

    Absolutely amazing guide. Legit most current and useful one to date. Can I ask how it will handle going to production with this in a web app.

    • Piotr Jaworski

      @domitriusclark:disqus Here is a great screencast how to handle it on production! https://gorails.com/episodes/deploy-actioncable-and-rails-5

      • Domitrius Clark

        I’m going through Heroku and am fully deployed, but the chat is not auto updating, so I’m assuming there’s an issue in the way i set it up! The messages are storing properly, but I have to refresh the page to see them.

        • Piotr Jaworski

          Did you add Redis to your Heroku application?

  • 蔡子揚

    Some typing error
    Adding first views >> Add the conversations/_converastion.html.erb file:

    file name error : _conver “as” tion.html.erb

    • Piotr Jaworski

      Good catch!

  • Scott Hoch

    Great article Thanks for posting. Added an additional method to guard on conversation creation

    def self.get_or_create(sender_id, recipient_id)
    return unless sender_and_recipient_exist?(sender_id, recipient_id)
    conversation = between(sender_id, recipient_id).first
    return conversation if conversation.present?

    create(sender_id: sender_id, recipient_id: recipient_id)

    def self.sender_and_recipient_exist?(sender_id, recipient_id)
    User.where(id: sender_id).exists? && User.where(id: recipient_id).exists?

  • Harsh Pathak

    What happens if someone attacks by trying to pass in random conversation ids and random user_ids to create messages? Wouldn’t it be better to get id from current_user.id in messages_controller instead from message_params? And also have the user pass recipient’s id so conversation can be found that way instead of getting conversation id from your html?

  • Carlos Cuesta Callejas

    this firts part now working

  • Ishita Singh Bhadoria

    Hi , after doing all of it I am getting this .Please help.