Ruby on Rails

 

Ruby on Rails Tutorial: Understanding ActionCable and WebSockets

In today’s web development landscape, users expect dynamic and real-time features in their applications. Traditional request-response cycles might not always be sufficient to provide a seamless user experience. To address this need, Ruby on Rails introduced ActionCable, a powerful framework for building real-time web applications using WebSockets. In this tutorial, we’ll delve into ActionCable and WebSockets and learn how to integrate them into your Rails applications.

Ruby on Rails Tutorial: Understanding ActionCable and WebSockets

1. Understanding WebSockets

Traditional web applications rely on the request-response model, where the client sends a request to the server, which then processes it and sends back a response. This approach works well for many scenarios, but it falls short when it comes to real-time communication.

WebSockets are a bi-directional communication protocol that allows continuous communication between the client and the server. Unlike HTTP, WebSockets maintain an open connection, enabling real-time data transfer. This persistent connection eliminates the need for constant polling, reducing latency and enhancing the overall user experience.

2. Introducing ActionCable

ActionCable, introduced in Rails 5, is an integrated WebSocket framework designed to simplify real-time communication in Rails applications. It seamlessly integrates WebSockets into the Rails stack, making it easy for developers to add real-time features without the need for additional third-party libraries.

ActionCable operates with “channels” that represent communication streams between the server and clients. Channels can broadcast messages to multiple subscribers, allowing you to create chat applications, notifications systems, live updates, and more.

3. Setting Up ActionCable in Your Rails Application

Before we begin using ActionCable, ensure you have a Rails application up and running. If you don’t have one, create a new Rails project using:

bash
rails new RealTimeApp
cd RealTimeApp

ActionCable is included in Rails by default, so there’s no need to install any additional gems. However, you must run the following command to generate the necessary files:

bash
rails generate channel Chat

This will create the ChatChannel in the app/channels directory and a corresponding JavaScript file in app/assets/javascripts/channels.

4. Creating a Real-Time Chat Application

Let’s implement a simple real-time chat application to grasp the fundamentals of ActionCable and WebSockets.

4.1. Setting Up the Project

First, we’ll set up the Rails application and prepare the database:

bash
# Create a new Rails application
rails new RealTimeChatApp

# Move to the application's directory
cd RealTimeChatApp

# Generate the Chat model and database schema
rails generate model Chat username:string message:string
rake db:migrate

4.2. Building the Chat Interface

Next, we’ll create a basic interface using HTML, CSS, and JavaScript to send and display messages:

html
<!-- app/views/chats/index.html.erb -->
<!DOCTYPE html>
<html>
<head>
  <title>Real-Time Chat</title>
  <style>
    /* Add your CSS styles here */
  </style>
</head>
<body>
  <div id="chat-container">
    <div id="chat-messages"></div>
    <input type="text" id="username" placeholder="Username">
    <input type="text" id="message" placeholder="Type your message">
    <button id="send-button">Send</button>
  </div>
  <script>
    // Add your JavaScript code here
  </script>
</body>
</html>

4.3. Implementing the Real-Time Communication

To enable real-time communication, we’ll leverage ActionCable. First, let’s modify the ChatChannel to handle subscriptions and broadcasting:

ruby
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from 'chat_channel'
  end

  def receive(data)
    Chat.create(username: data['username'], message: data['message'])
  end
end

The subscribed method is automatically called when a client subscribes to the channel. In this case, we’re streaming messages to the ‘chat_channel’. The receive method handles incoming data from clients and creates a new Chat record in the database.

Now, let’s implement the JavaScript code to handle client-side communication and update the chat interface:

javascript
// app/assets/javascripts/channels/chat.js
document.addEventListener('DOMContentLoaded', function () {
  const chatContainer = document.getElementById('chat-container');
  const chatMessages = document.getElementById('chat-messages');
  const usernameInput = document.getElementById('username');
  const messageInput = document.getElementById('message');
  const sendButton = document.getElementById('send-button');

  // Establish a WebSocket connection with ActionCable
  const cable = ActionCable.createConsumer();
  const chatChannel = cable.subscriptions.create('ChatChannel', {
    received: function (data) {
      const messageDiv = document.createElement('div');
      messageDiv.innerText = `${data.username}: ${data.message}`;
      chatMessages.appendChild(messageDiv);
    },
  });

  sendButton.addEventListener('click', function () {
    const username = usernameInput.value;
    const message = messageInput.value;
    chatChannel.send({ username: username, message: message });
    messageInput.value = '';
  });
});

The JavaScript code sets up an ActionCable connection, listens for incoming messages, and appends them to the chat interface.

5. Broadcasting Updates Across Clients

In the current implementation, new messages are only sent to the server. To broadcast them to all connected clients, we’ll modify the receive method in the ChatChannel:

ruby
# app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from 'chat_channel'
  end

  def receive(data)
    Chat.create(username: data['username'], message: data['message'])
    ActionCable.server.broadcast('chat_channel', data)
  end
end

Now, when a message is received, we create a new Chat record as before, and then use ActionCable.server.broadcast to send the message data to all subscribed clients.

6. Handling Advanced Scenarios

In real-world applications, there are several additional considerations to address. Let’s explore two common scenarios: authorization and authentication, and handling connection failures.

6.1. Authorization and Authentication

To ensure only authenticated users can access the chat, you can implement authentication using popular gems like Devise or Clearance. Once authentication is set up, you can access the current user’s information within the ChatChannel and restrict access if needed.

6.2. Handling Connection Failures

Occasionally, WebSocket connections may fail due to network issues or server problems. To handle such cases gracefully, you can utilize ActionCable’s disconnected callback in the ChatChannel. This method is triggered when a client loses connection to the server, allowing you to perform cleanup tasks or inform other users about the disconnection.

7. Performance and Scalability Considerations

As your real-time application grows, you may encounter performance and scalability challenges. To optimize ActionCable’s performance, consider deploying a WebSocket server (such as Puma) alongside your Rails application. Additionally, scaling ActionCable using solutions like Redis or RabbitMQ can improve performance when handling a large number of WebSocket connections.

Conclusion

In this tutorial, we explored the power of ActionCable and WebSockets in Ruby on Rails applications. We learned how to set up ActionCable, create real-time chat functionality, and broadcast updates across clients. Additionally, we discussed handling advanced scenarios, performance optimization, and scalability considerations. With this knowledge, you can enhance the user experience of your Rails applications and build feature-rich real-time web applications.

Remember, real-time communication opens up a world of possibilities for interactivity and user engagement. Whether you’re building chat applications, live notifications, collaborative tools, or interactive games, ActionCable and WebSockets are valuable tools to take your Rails projects to the next level. Happy coding!

Previously at
Flag Argentina
Brazil
time icon
GMT-3
Senior Software Engineer with a focus on remote work. Proficient in Ruby on Rails. Expertise spans y6ears in Ruby on Rails development, contributing to B2C financial solutions and data engineering.