DEV Community

Paweł Dąbrowski
Paweł Dąbrowski

Posted on

Solution for those who like Action Cable but hate writing JavaScript

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

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.

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:

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:

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

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:

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 %>

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

Real-time chat first version

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:

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:

*= 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:

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

<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

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

Top comments (0)