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!