Solution for those who like Action Cable but hate writing JavaScript
Tags: ruby, javascript, rails
Published: 2020-07-21 13:02:02

## Introduction

**Cable Ready** is a great addition for Action Cable, especially if you don't like to write JavaScript code to interact with your website's DOM in a real-time. It helps us to quickly write real-time applications that work out of the box.

To demonstrate the features that the gem provides, we will build a simple chat where new messages will appear on the website without reloading. We will start with creating a brand-new Rails application, creating a little code, adding the **Cable Ready** gem, and making things real-time.

### Demo

At the end of the article, we will have fully working simple chat:

![Real-time chat example](https://s3-us-west-1.amazonaws.com/pdabrowski.com/articles/cable-ready-rails/cableready.gif)

## Creating example application

Our application will consist of only one model: `Message`. The model will have the following columns: `username` and `body`. The main purpose of the application is to let guests to simply write messages on the chat.

### Application sekeleton

We will use Ruby `2.7.0` and Rails in version `6.0.3.2` . Since we don't need anything fancy on the database side, we will use `SQLite` as a database engine.

```ruby
rails new chat
cd chat
```

### Model

As mentioned before, we would need one model - `Message` where we will save the guest username along with the message that will appear in the chat. Let's create it:

```ruby
rails g model Message username:string body:text
rails db:setup
rails db:migrate
```

### Controller

We will need a controller to display messages and save new messages. Let's create one and save the following code into `app/controllers/messages_controller.rb`:

```ruby
class MessagesController < ApplicationController
  def index
    @message = Message.new
    @messages = Message.order('created_at DESC')
  end

  def create
    Message.create!(message_params)
    
    redirect_to :messages
  end

  private

  def message_params
    params.require(:message).permit(:username, :body)
  end
end
```

update routes in `config/routes.rb`

```ruby
Rails.application.routes.draw do
  resources :messages, only: %i[index create]
  root to: 'messages#index'
end
```

and create `app/views/messages/index.html.erb` view:

```ruby
Current messages:

<ul>
  <% @messages.each do |message| %>
    <li><%= message.username %>: <%= message.body %>
  <% end %>
</ul>

<h2>Add new message:</h2>

<%= form_for(@message) do |f| %>
  <%= f.text_field :username, placeholder: 'username' %>
  <%= f.text_area :body, placeholder: 'message' %>
  <%= f.submit 'Send' %>
<% end %>
```

<!--- insert_newsletter_widget -->

Now our "application" works but looks terrible and page is reloading each time we hit the `Send` button.

![Real-time chat first version](https://s3-us-west-1.amazonaws.com/pdabrowski.com/articles/cable-ready-rails/cableready1.png)

## Adding proper styles to the application

Before we add Cable Ready to our application, let's refactor the look a little bit so it looks more like a web chat.

### Bootstrap installation

We will use the Bootstrap framework to save tons of time and adding nicely look to our simple application. The installation process is simple and consists of two steps. The first one is to install the library using yarn:

```ruby
yarn add bootstrap@4.3.1
```

and the second one is to load styles. Update `app/assets/stylesheets/application.css` and add the following line:

```ruby
*= require bootstrap
```

### Updating styles of messages list and new message form

Make sure that your `app/views/layouts/application.html.erb` looks like the following:

```ruby
<!DOCTYPE html>
<html>
  <head>
    <title>Chat</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <div class="flex-md-row p-3 px-md-4 mb-3 bg-white border-bottom box-shadow">
      <h5 class="text-center">Simple chat</h5>
    </div>
    <div class="container">
      <%= yield %>
    </div>
  </body>
</html>
```

and `app/views/messages/index.html.erb` :

```ruby
<div class="row justify-content-center">
  <div class='col-6'>
    <div class="list-group" id="messages">
      <% @messages.each do |message| %>
        <a href="#" class="list-group-item list-group-item-action">
          <p class="mb-1"><%= message.body %></p>
          <small class="text-muted"><%= message.username %></small>
        </a>
      <% end %>
    </div>
  </div>
</div>
<div class="row justify-content-center">
  <div class='col-6'>
    <hr class="mt-3 mb-3"/>
    <h2>Add new message:</h2>
        
    <%= form_for(@message) do |f| %>
      <div class="form-group">
        <label>Username</label>
        <%= f.text_field :username, placeholder: 'username', class: 'form-control' %>
      </div>
      <div class="form-group">
        <label>Message</label>
        <%= f.text_area :body, placeholder: 'message', class: 'form-control' %>
      </div>
      <%= f.submit 'Send', class: 'btn btn-primary' %>
    <% end %>
  </div>
</div>
```

Now our application looks way better:

![Real-time chat updated version](https://s3-us-west-1.amazonaws.com/pdabrowski.com/articles/cable-ready-rails/cableready2.png)

## Making our chat real-time

It's time to update our code so new chat messages will appear without reloading the whole page. In the first step, we will update the form so the request will be sent in the background via AJAX, not as the normal POST request with redirection. In the second step, we will finally add ActionCable along with CableReady to make real-time updates.

Continue reading on https://pdabrowski.com/articles/cable-ready-with-action-cable