Blog

Real Time Data With Rails

David Ang
December 14, 2023

I was tasked to perform optimization on a page that performs heavy calculations. The page would often take minutes for all the data to load. Optimizing pages to minimize lengthy wait times, helps to reduce frustrations for users.

A great solution is to provide immediate feedback to the user by pre-loading the page, and fetching each part separately with Action Cable. Action Cable is a Rails framework for real-time features, allowing updates to be sent to the user’s browser as they happen.

Setup the Action Cable configuration:

yaml
# config/cable.yml
development:
  adapter: redis
  url: redis://localhost:6379/1

Now we’ll need some background processing. For this, I recommend sidekiq. Sidekiq is a background processing tool for Ruby that will handle our heavy lifting without blocking the main thread.

I created an Active Job for the calculation and the job communicates the data back via Action Cable.

ruby
# config/routes.rb
require 'sidekiq/web'
Rails.application.routes.draw do
  devise_for :users
  
  authenticate :user, lambda { |user| user.admin? } do
    mount Sidekiq::Web, at: "/sidekiq"
  end
end

Let’s also create the channel and let Rails know what channel name we are streaming from.

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

  def unsubscribed
    stop_all_streams
  end
end

Next we’ll create an Active Job that Sidekiq will process. The job will deliver the message back to the website once it finishes all the heavy lifting. Note the channel name that we broadcast the data to, it’s the same channel name we defined in our PortfolioChannel class.

ruby
class CheckComplianceJob < ApplicationJob
  queue_as :default

  def perform(portfolio_id:)
    portfolio = Portfolio.find_by(id: portfolio_id)
    
    calculated_result = do_some_heavy_calculation
    
    ActionCable.server.broadcast 'PortfolioChannel', {
      data: calculated_result
    }
  end
end

We’ll also need javascript to receive the data and update our page in real-time. Like before we are using the same channel name.

javascript
App.cable.subscriptions.create('PortfolioChannel', {
  connected: function() {},
  disconnected: function() {},
  received: function(data) {
    // Update your UI from data 
  }
});

If you’d like help in making your site more reactive and snappy for your users, please don’t hesitate to get in touch with us. Thanks for reading, no matter your software problem, we provide a complete solution to scope, design, develop, test, host, maintain and support it 24/7/365. Contact us to find out how can we bring your ideas to reality!