WebSockets in Rails

Written by

In today's world, real-time communication has become an essential feature of many web applications. WebSockets provide a way to achieve this in a fast, reliable, and efficient manner. In this blog post, we will dive into WebSockets in Rails and how they can be used to build real-time applications.

What are WebSockets?

WebSockets are a protocol that provides full-duplex communication between a client and servers. Unlike traditional HTTP requests, WebSockets maintain an open connection between the client and the server, allowing real-time communication. WebSockets are useful in a variety of applications, including chat systems, online games, and real-time data displays.

Using WebSockets in Rails

Rails provide support for WebSockets through its Action Cable framework. Action Cable enables developers to add real-time functionality to their applications easily. To use WebSockets in Rails, you need to set up a channel, which is a communication channel that allows the client and server to send and receive data.

Here's how you can set up a WebSocket channel in Rails:

Create a new channel

You can create a new channel in Rails using the following command:

rails generate channel <channel_name>

This will generate a new channel in the app/channels directory.

Implement the channel

Next, you need to implement the channel by defining the actions that can be performed on it. For example, let's say you have a chat channel that allows users to send and receive messages.

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

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def speak(data)
    ActionCable.server.broadcast "chat_#{params[:room]}", message: data['message']
  end
end

In this example, the subscribed method is called when the client subscribes to the channel. It uses the stream_from method to start streaming data from the channel. The unsubscribed method is called when the client unsubscribes from the channel. The speak method is called when the client sends data to the channel.

Handling lost connections: WebSockets are built on top of the TCP protocol, which provides reliability and fault tolerance. However, in case of a lost connection, the server will not be notified until it tries to send data and fails. To handle lost connections, you can implement a heartbeat mechanism where the client periodically sends a message to the server to indicate that it is still connected. If the server does not receive a heartbeat within a certain timeframe, it can assume that the connection has been lost and take appropriate action (e.g., stop sending messages or remove the client from the channel).

Sending data from the client to the server: When the client sends data to the server via a WebSocket connection, it can be sent as a string, JSON, or any other format that can be serialized. In Rails, you can use the speak method (or any other name you choose) to handle incoming data from the client. The data can be accessed via the data parameter of the method, which contains the payload sent by the client.

Ruby handling of session alive: By default, Rails uses a cookie-based session stored to maintain the session state for each client. The session data is stored on the server and identified by a session ID that is stored in a cookie on the client's browser. When a client connects to a WebSocket channel, the session ID can be passed as a parameter in the WebSocket URL. The server can then use this ID to retrieve the session data and keep the session alive. However, it's important to note that WebSocket connections are stateful, which means that the server maintains a connection with the client for the duration of the session. This can put a strain on server resources if there are many clients connected at the same time.

Create a view

Finally, you need to create a view that displays the data sent over the WebSocket. The example given below uses Vanilla JavaScript. However, using a framework such as React or Vue.js is recommended to create a view that displays the data sent over the WebSocket.

App.chat = App.cable.subscriptions.create("ChatChannel", {
  connected: function() {
    // Called when the subscription is ready for use on the server
  },

  disconnected: function() {
    // Called when the subscription has been terminated by the server
  },

  received: function(data) {
    // Called when there's incoming data on the websocket for this channel
  }
});

In this example, the connected method is called when the subscription is ready to use on the server. The disconnected method is called when the server has terminated the subscription. The received method is called when there is incoming data on the WebSocket for this channel.

You can use the received method to tie the data received over the WebSocket to an input or other element in your view. You can use the received method. This method is called when there is incoming data on the WebSocket for this channel.

For example, let's say you have an input field with the id #chat-input and a div with the id #chat-messages in your view. You can update the #chat-messages div content with the data received over the WebSocket, like presented below:

App.chat = App.cable.subscriptions.create("ChatChannel", {
  connected: function() {
    // Called when the subscription is ready for use on the server
   },

   disconnected: function() {
      // Called when the subscription has been terminated by the  server
   },

   received: function(data) {
     // Called when there's incoming data on the websocket for this channel
   $("#chat-messages").append("<p>" + data.message + "</p>");
   }
});

In the example above, we're using jQuery to select the #chat-messages div and append a new paragraph element with the received data. This code can be modified to update any element on the web page with the data received over the WebSocket.

Therefore, WebSockets provide a powerful way to add real-time functionality to your web applications. And Rails, through its ActionCable framework, makes it much easier to add WebSockets.