Real-Time Streaming with Ruby on Rails: A Step-by-Step Guide
In today’s fast-paced digital world, real-time updates are becoming increasingly essential. Whether you’re building a live chat application, a stock ticker, or any feature that benefits from instant updates, streaming responses can significantly enhance the user experience. In this article, we’ll explore how to implement streaming responses in a Ruby on Rails application.
Why Streaming?
Streaming allows your server to push updates to the client as soon as they happen, without the need for the client to continuously poll the server for new data. This results in more efficient resource usage and a smoother user experience.
Setting Up Streaming in Rails
To illustrate how to set up streaming in Rails, we’ll walk through a simplified example. We’ll create a MessagesController
that handles both standard and streaming responses.
Step 1: Include ActionController::Live
First, include ActionController::Live
in your controller. This module provides the necessary functionality for streaming responses.
class MessagesController < ApplicationController
include ActionController::Live
def create
params = message_params
prompt = params[:prompt]
stream = params[:stream] == 'true'
if stream
handle_streaming_response(prompt)
else
handle_standard_response(prompt)
end
end
private
def message_params
params.require(:message).permit(:prompt, :stream)
end
end
Step 2: Handling Streaming Responses
In the handle_streaming_response
method, we set the Content-Type
header to text/event-stream
and initialize an SSE
(Server-Sent Events) object. We then call our service to handle the streaming.
def handle_streaming_response(prompt)
response.headers['Content-Type'] = 'text/event-stream'
sse = SSE.new(response.stream, retry: 300, event: 'open')
begin
GatewayService.new(prompt: prompt, stream: true).call do |chunk|
sse.write(chunk, event: 'response')
end
rescue StandardError => e
Rails.logger.error "Error during streaming: #{e.message}"
ensure
sse.close
response.stream.close
end
end
Step 3: Gateway Service
The GatewayService
is responsible for interfacing with external APIs and streaming data back to the controller. Here’s a minimal version focused on streaming:
class GatewayService
def initialize(options)
@prompt = options[:prompt]
@stream = options[:stream]
end
def call(&block)
if @stream
simulate_streaming(&block)
else
{ message: "Standard response for #{@prompt}" }
end
end
private
def simulate_streaming
5.times do |i|
sleep 1
yield "Chunk #{i + 1}: Response for #{@prompt}"
end
end
end
Running the Example
To test this setup, you can use a tool like curl to simulate a client request:
curl -N -H "Accept: text/event-stream" -d "message[prompt]=Hello&message[stream]=true" http://localhost:3000/messages
This will initiate a streaming connection, and you should see the streamed chunks arriving one by one.
Conclusion
Implementing streaming in a Ruby on Rails application is straightforward with the ActionController::Live
module. By properly handling streaming responses, you can create applications that provide real-time updates to users, greatly enhancing the user experience. Whether you are working on a chat application, live notifications, or data feeds, streaming is a powerful tool in your Rails development toolkit.
Happy coding!