Building a Real-Time Application with Ruby on Rails and Action Cable

Ruby on Rails has long been a powerhouse for developing robust web applications. With Rails 5, a new gem called Action Cable was introduced, enabling developers to integrate real-time features into their applications. This addition marks a new era for Rails, bridging the gap between traditional web applications and the more dynamic, ever-changing web experiences users expect today. If you're intrigued by creating real-time, interactive features in your Rails app, this blog will guide you through using Action Cable effectively.

Understanding Real-Time Applications and Action Cable

Real-time applications are those where information is constantly updated, unconfined by the traditional request-response cycle. These are ubiquitous today—think of live chat applications, online gaming, real-time notifications in management systems, and more. Essentially, they provide users with timely updates as events occur.

Action Cable is Rails' built-in WebSockets framework that allows Rails applications to achieve these real-time capabilities. Unlike HTTP, WebSockets facilitate two-way communication between client and server, maintaining a persistent connection that enhances the real-time communication experience.

Setting Up Action Cable in Your Rails Application

To embark on building a real-time application with Action Cable, ensure your Rails application is version 5 or newer, as this feature is natively integrated from this version onwards.

  1. Configure Your Rails App: First, incorporate Action Cable into your configuration by adjusting your config/cable.yml to match your setup, whether you're deploying locally or using a cloud service.

    yaml
    1development:
    2 adapter: redis
    3 url: redis://localhost:6379/1
    4 channel_prefix: your_app_development
    5
    6production:
    7 adapter: redis
    8 url: <%= ENV['REDIS_URL'] %>
    9 channel_prefix: your_app_production

    Redis is commonly used here to manage these concurrent connections effectively.

  2. Generate an Action Cable Channel: Channels in Action Cable serve as the framework for client-server communication. Generate a new channel via the Rails generator:

    text
    1rails generate channel Chat

    This creates a server-side chat_channel.rb and client-side files. The channel represents a shared communication line, a pathway through which messages are dispatched.

Crafting Channels and Consumers

In your server-side chat_channel.rb, define how your server interacts with connected clients. Here, for example, is a simple way you can display a message when a user connects or disconnects:

ruby
1class ChatChannel < ApplicationCable::Channel
2 def subscribed
3 stream_from "chat_channel"
4 ActionCable.server.broadcast "chat_channel", message: "#{current_user.name} connected."
5 end
6
7 def unsubscribed
8 ActionCable.server.broadcast "chat_channel", message: "#{current_user.name} disconnected."
9 end
10end

Consumers - The client-side part of an Action Cable channel is handled by a consumer. The consumer establishes a persistent connection to the server using WebSockets and updates the UI client-side when broadcast messages are received. In JavaScript, set up your consumer and initialize a subscription:

javascript
1import consumer from "./consumer"
2
3consumer.subscriptions.create("ChatChannel", {
4 connected() {
5 console.log("Connected to the chat channel.")
6 },
7
8 disconnected() {
9 console.log("Disconnected from the chat channel.")
10 },
11
12 received(data) {
13 document.querySelector('#messages').insertAdjacentHTML('beforeend', `<p>${data.message}</p>`)
14 }
15});

The above JavaScript listens for messages from the ChatChannel and dynamically updates the page.

Broadcasting Messages in Action Cable

Broadcasting involves sending messages from the server to all or specific client(s) over a channel. Here's an example of broadcasting in a Rails controller action:

ruby
1class MessagesController < ApplicationController
2 def create
3 message = Message.new(message_params)
4 if message.save
5 ActionCable.server.broadcast "chat_channel", message: render_message(message)
6 end
7 end
8
9 private
10
11 def render_message(message)
12 ApplicationController.renderer.render(partial: 'messages/message', locals: {message: message})
13 end
14
15 def message_params
16 params.require(:message).permit(:content)
17 end
18end

The broadcast sends the new message as it is created, which is then processed client-side by the JavaScript consumer to display in real-time.

Handling Real-Time Data Updates

Real-time data updates are critical for providing an interactive user experience. In dynamic applications like live chat or collaborative tools, users expect instantaneous feedback. Action Cable makes it straightforward to accommodate these demands.

For instance, in the chat application example, the moment a new message is deposited into the database, it can be broadcast and displayed immediately across all connected clients. This architecture can be extended to handle live updating dashboards, real-time collaborative documents, or any scenario requiring synchronous updates.

Practical Example: Creating a Chat Application

To define the extent of Action Cable's power, let’s pursue a specific example—building a lightweight real-time chatroom:

  1. Generating Models and Controllers: Set up models and controllers for messages or any entities you intend to manage within your chatroom.

    shell
    1rails generate model Message content:text user:references
    2rails generate controller Messages
  2. Frontend Integration: Leverage JavaScript to maintain the live chat by dynamically handling user inputs and outputs.

    javascript
    1document.addEventListener('DOMContentLoaded', () => {
    2 const form = document.querySelector('#new_message');
    3 if (form) {
    4 form.addEventListener('submit', event => {
    5 event.preventDefault();
    6 const textbox = form.querySelector('#message_content');
    7 let content = textbox.value;
    8
    9 fetch('/messages', {
    10 method: 'POST',
    11 body: JSON.stringify({ message: { content } }),
    12 headers: { 'Content-Type': 'application/json' }
    13 });
    14 textbox.value = '';
    15 });
    16 }
    17});
  3. Deployment Considerations: Bear in mind that deploying an Action Cable application requires persistence solutions like Redis for production environments, which easily manage concurrent WebSocket connections and broadcasts.

Conclusion

Building real-time web applications with Ruby on Rails and Action Cable significantly enhances the interactivity and responsiveness of your applications. This step-by-step guide introduces the vital components of Action Cable: channels, consumers, and broadcasting architecture. By integrating these patterns, you can breathe life into your Rails apps, crafting experiences akin to those of highly reactive platforms.

In terms of scalability and user engagement, leveraging WebSockets through Action Cable ensures your applications are a step ahead, providing the contemporary interactive experiences today’s web users have come to expect.

For further reading:

By harnessing the power of Action Cable, you're not just future-proofing your applications—you're positioning them at the forefront of interactive web development.

Suggested Articles