Understanding Action Cable in Ruby on Rails: A Comprehensive Guide

November 22, 2024

Action Cable is a powerful framework in Ruby on Rails that allows for real-time features in web applications using WebSockets. It integrates seamlessly with Rails, making it easy to add real-time capabilities like chat, notifications, and live updates without losing the elegance and scalability of Rails. This article delves into the core concepts, components, and client-server interactions involved in Action Cable.


1. What is Action Cable?

Action Cable is designed to bring WebSockets into the Rails ecosystem in a way that fits naturally with Rails’ convention-over-configuration philosophy. Unlike the traditional HTTP request-response model, WebSockets offer a persistent connection between the client and server, enabling real-time communication. Action Cable bridges this gap by offering both a server-side Ruby framework and a client-side JavaScript framework, allowing you to interact with your entire domain model written with Active Record or any ORM you choose.

2. Key Terminology

Action Cable uses specific terminology to describe its components and interactions:

2.1 Connections

Connections are the foundation of the WebSocket communication between the client and server. Each connection instance is tied to a single WebSocket, and a user may have multiple connections if they open multiple browser tabs or use different devices. Connections are essential for maintaining real-time communication.

2.2 Consumers

The consumer is the client-side WebSocket, typically created using JavaScript. Each connection can have one or more consumers.


🚀 Need Expert Ruby on Rails Developers to Elevate Your Project?

Fill out our form! >>

🚀 Need Expert Ruby on Rails Developers to Elevate Your Project?

2.3 Channels

A channel in Action Cable is similar to a controller in Rails. It defines a logical unit of work, and consumers can subscribe to multiple channels. Examples of channels include a ChatChannel for real-time chat or an AppearancesChannel for live notifications.

2.4 Subscribers

When a consumer subscribes to a channel, it becomes a subscriber. A subscriber can be connected to one or more channels, depending on the use case.

2.5 Pub/Sub (Publish-Subscribe)

Pub/Sub is a messaging pattern where data is published by a sender (the publisher) and delivered to all relevant subscribers without explicitly targeting individual subscribers. Action Cable uses this approach to broadcast messages to multiple clients simultaneously.

2.6 Broadcasting

Broadcasting in Action Cable refers to sending data from the server to multiple subscribers in a channel. It works with the Pub/Sub model to deliver real-time updates to all subscribers of a given channel.

3. Server-Side Components

3.1 Connections

When a WebSocket connection is established, a connection object is created on the server side. This object handles the WebSocket lifecycle, such as authentication, authorization, and setting up subscriptions. Connections are instances of ApplicationCable::Connection and inherit from ActionCable::Connection::Base.

3.1.1 Connection Setup

In the following example, we authenticate the user by checking a cookie that contains the encrypted user ID.

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

    def find_verified_user
      if verified_user = User.find_by(id: cookies.encrypted[:user_id])
        verified_user
      else
        reject_unauthorized_connection
      end
    end
  end
end

3.2 Channels

A channel defines the interaction between the server and the connected consumers. Channels are created by inheriting from ApplicationCable::Channel, and they handle the specific logic for each type of real-time interaction.

3.2.1 Channel Setup

Example of a ChatChannel:

class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat_#{params[:room]}"
  end
end

3.3 Subscriptions

Consumers subscribe to a channel, which allows them to receive messages sent to that channel. For example, a consumer could subscribe to a chat room.

3.3.1 Exception Handling

You can handle exceptions in channels using rescue_from:

class ChatChannel < ApplicationCable::Channel
  rescue_from "MyError", with: :deliver_error_message

  private

  def deliver_error_message(e)
    # Broadcast an error message to the channel
  end
end

4. Client-Side Components

4.1 Connections

On the client side, the consumer is created to establish a WebSocket connection. Rails provides an automatic JavaScript consumer setup in app/javascript/channels/consumer.js.

import { createConsumer } from "@rails/actioncable"
export default createConsumer()

4.2 Subscribers

Once the consumer is established, it can subscribe to a channel using the following JavaScript code:

import consumer from "./consumer"

consumer.subscriptions.create({ channel: "ChatChannel", room: "Best Room" })

A consumer can subscribe to multiple channels or rooms at once.

5. Client-Server Interactions

5.1 Streams

Streams are used to route broadcasts to subscribers. When a consumer subscribes to a channel, they start streaming messages from that channel.

class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat_#{params[:room]}"
  end
end

5.2 Broadcastings

Broadcasting is the core mechanism of Action Cable, where data is sent from the server to all subscribers of a given channel. For example:

ActionCable.server.broadcast("chat_Best Room", { body: "This Room is Best Room." })

5.3 Subscriptions

Each subscription represents a connection between a consumer and a channel. Messages are routed to subscribers based on the identifiers they pass during subscription creation.

5.4 Passing Parameters to Channels

You can pass parameters to channels to customize the connection. For example, a chat room might use a room identifier:

consumer.subscriptions.create({ channel: "ChatChannel", room: "Best Room" })

On the server side, you can use these parameters to define the specific stream the consumer should listen to:

class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat_#{params[:room]}"
  end
end

Conclusion

Action Cable provides a robust solution for adding real-time capabilities to Rails applications. By leveraging WebSockets and the pub/sub pattern, Action Cable allows developers to build scalable, responsive features such as chat applications, live notifications, and data-driven updates. The combination of server-side Ruby and client-side JavaScript frameworks makes it an integral part of Rails’ full-stack capabilities for real-time communication. Whether you’re building a simple chat feature or a complex real-time notification system, Action Cable’s integration with Rails provides a seamless, powerful approach.

Leave a comment