Skip to Content

Building a Chat App with Solid Cable: Simplifying Real-Time Communication


In today’s fast-paced world, seamless communication is the backbone of both personal and professional connections. Real-time chat applications have become essential, enabling instantaneous interactions across geographies and time zones. In this article, we explore how one can build a simple yet effective chat application with Solid Cable, simplifying the development of real-time communication features.

Solid Cable is an incredibly powerful tool that simplifies the process of building chat applications. It offers a developer-friendly interface and an efficient design, making it easy to integrate real-time messaging features into a Rails application. Whether building a platform for professional collaboration or a social messaging app, Solid Cable stands out as the go-to solution for a scalable and robust communication system.

To demonstrate how to build a chat application, we will walk through the process of creating a basic Rails 8 app. This example is minimal yet highly effective, showcasing how to integrate Solid Cable for real-time messaging functionality.


Getting Started with the App

First, ensure that Ruby and Rails 8 are installed on your system. If not, check out this guide to install Ruby and Rails.

Once that’s in place, the next step is to create a new Rails app:

rails new chat_app -c tailwind


Now, a model, controller, and views will be set up to kickstart the application. First, navigate to the app directory and then generate the model, controller, and index view using the following commands:

# change into the app directory
cd chat_app

# generate the Chat model and controller
rails g model chat message:string
rails g controller chats index create

# migrate the database
rails db:migrate


At this point, the code should be updated in the relevant files. Since this is a basic Rails setup, the explanation is minimal, but more details will be provided when we integrate Solid Cable’s real-time capabilities.

Here’s the required code to replace the existing content:

config/routes.rb

Rails.application.routes.draw do
  resources :chats
  root "chats#index"
end


app/controllers/chats_controller.rb

class ChatsController < ApplicationController
  def index
    @chats = Chat.all
  end

  def create
    @chat = Chat.build(chat_params)
    @chat.save

    redirect_to chats_path
  end

  private

  def chat_params
    params.require(:chat).permit(:message)
  end
end


app/views/chats/index.html.erb

<div class="w-1/2">
  <h1 class="mb-6 text-slate-700 font-bold text-2xl">Chats</h1>
  <div class="space-y-4 mb-8">
    <div id="chats">
      <%= render @chats %>
    </div>
  </div>
  <%= render "form" %>
</div>


Adding the Form and Chat Partials

Two partials are necessary: one for the input form and one for individual chat messages.

app/views/chats/_form.html.erb

<%= form_with model: Chat.new, local: false do |f| %>
  <div class="flex">
    <%= f.text_field :message,
        autocomplete: :off,
        class: "block w-2/3 rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400",
        placeholder: "enter message..." %>
    <%= f.submit "Send",
        class: "inline-flex w-1/3 items-center justify-center rounded-md bg-slate-400 ml-3 px-3 py-2 text-sm font-semibold text-white shadow-sm" %>
  </div>
<% end %>


app/views/chats/_chat.html.erb

<div>
  <div class="flex justify-between items-start">
    <div class="text-gray-700">
      <%= chat.message %>
    </div>
    <div class="text-sm text-gray-400">
      <%= time_ago_in_words(chat.created_at) %> ago
    </div>
  </div>
</div>


Running the Basic App

By following the steps above, the basic app can now be launched using bin/dev in the terminal. The app should be accessible at http://localhost:3000, where users can enter messages that will be displayed above the input field. However, at this stage, messages won’t update in real time across different sessions. To add real-time functionality, Solid Cable will now be introduced to handle WebSockets.


Integrating Solid Cable

With the basic app in place, it’s time to bring Solid Cable into the mix. If using Rails 8.0.0, Solid Cable is included by default, so there’s no extra setup required. However, for earlier versions of Rails, it’s necessary to install the gem:

bundle add solid_cable
bin/rails solid_cable:install


Configuring Solid Cable

The main configuration file for Action Cable is config/cable.yml. In the development section, the adapter is typically set to “async,” but since Solid Cable will be used, the configuration should be updated. The development section of config/cable.yml should look like this:

development:
  adapter: async

to:

development:
  adapter: solid_cable
  connects_to:
    database:
      writing: cable
  polling_interval: 0.1.seconds
  message_retention: 1.day


Next, configure the database for Solid Cable. A separate database needs to be created to store messages. This is done by modifying the config/database.yml file:

development:
  <<: *default
  database: storage/development.sqlite3

to:

development:
  primary:
    <<: *default
    database: storage/development.sqlite3
  cable:
    <<: *default
    database: storage/development_cable.sqlite3
    migrations_paths: db/cable_migrate


After modifying the database configuration, the database should be initialized with:

rails db:prepare


Enabling WebSockets

Now it’s time to enable WebSockets for real-time updates. In the app/views/chats/index.html.erb file, the Turbo Stream tag will be added:

<div class="w-1/2">
  <h1 class="mb-6 text-slate-700 font-bold text-2xl">Chats</h1>
  <div class="space-y-4 mb-8">
    <%= turbo_stream_from "chats" %>
    <div id="chats">
      <%= render @chats %>
    </div>
  </div>
  <%= render "form" %>
</div>


Then, the Chat model is updated to broadcast messages after they’re created. In the app/models/chat.rb file, the following code is added:

class Chat < ApplicationRecord
  after_create_commit :broadcast_chat

  def broadcast_chat
    broadcast_append_to(
      "chats",
      target: "chats",
      partial: "chats/chat",
      locals: { chat: self }
    )
  end
end


Finally, since the page will be updated through WebSockets, there’s no need to redirect after creating a chat message. The create action in the chats_controller.rb file should simply render a json response with no content

In the app/controllers/chats_controller.rb file “create” action, simple replace the line

redirect_to chats_path

with

render json: {}, status: :no_content


Wrapping Up

That’s it! After restarting the server, try opening the app in two different browsers. When a message is sent from one browser, it should appear in the other in real time, without needing a page refresh.

By integrating Solid Cable, building real-time chat functionality in Rails has never been easier. With just a few lines of code, a fully interactive chat app is now running, allowing users to communicate seamlessly across devices.

Ruby on Rails 8: A Complete Breakdown of Features