Implementing Web Sockets in Rails 4

WebSockets can be implemented in Rails5 using ActionCable which can be used for enabling many features like chats, notifications, and other real-time modules. But, how does one achieve the same goal without ActionCable and Rails 5? This blog deals with how we can implement web sockets in Rails 4.

Before we start, we can have a quick look at the concept of web sockets.

The majority of the web is based on HTTP request/responses which are enabling the communication of many hosts and clients over TCP/IP transports. This means that web applications usually don’t do anything after a user visits them in a browser and parses the request and sends a response. Until the user clicks something on the page, the server won’t receive any new HTTP request and therefore it will stand idle.

There are technologies that enable the server to initiate communication with the client when there is data to be sent, such as “Push” or “Comet” and the long polling technique which keeps an HTTP connection open once a client connects to the server. The bad thing with these approaches is the overhead of HTTP which isn’t very good for low latency applications.

This is where Web sockets come into place. They are an API that provides “socket” persistent connections between a server and a client, which enables both to send data at any time

In this blog, we are creating an online cricket player auction site that uses web sockets in Rails 4. The site can be used by multiple users to bid for the same player. The challenge is to update the bid without reloading the page and keeping up the live communication.

Mainly three gems are used for implementing the web socket functionality

Gemfile

gem ‘faye’
gem ‘thin’, require: false
gem ‘render_sync’

The thin is a small and fast ruby server.It should be installed with faye as the faye gem doesnt work with servers like webrick.

The next important gem is faye.Faye is a set of tools for simple publish-subscribe messaging between web clients. It ships with easy-to-use message routing servers for Node.js and Rack applications, and clients that can be used on the server and in the browser.

The sync or render_sync gem is used to create real-time partials with Rails. Sync lets you render partials for models that, with minimal code, update in real-time in the browser when changes occur on the server.

Our objective is to have a functionality which allows displaying the bidded values on the show page of a user. The first step for implementing this is to install templates from the sync gem

rails generate sync:install

And require sync in our asset pipeline.

app/assets/javascripts/application.js

//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require sync
//= require_tree

The configuration script is required in the application layout

app/views/layouts/application.html.erb

<%= include_sync_config %>

We need to create a partial and store it in the directory views/sync/ as _bid_log_row.html.erb
This partial contains the value of the bid of the user. and it will look like

Current Bid:
<%= @bid_log.amount || ‘ — ‘ rescue nil%>

And in order to render this in the show page add the following lines in the users show page

app/views/users/show.html.erb

<%= sync partial: ‘bid_log_row’, resource: @bid_log %>
<%= sync_new partial: ‘bid_log_row’, resource: BidLog.new %>

And lastly, make the changes in the BidLogsController so it knows how to handle remote form submissions, but also to sync the new bids in place.

class BidLogsController < ApplicationController
respond_to :html, :js
 def index
@bid_logs = BidLog.all
@new_bid = current_user.bid_logs.build
end
 def create
@bid_log = current_user.bid_logs.build(bid_log_params)
if @bid_log.save
sync_new @bid_log
end
respond_to do |format|
format.html { redirect_to user_path(@bid_log.player_id) }
format.json { head :no_content }
end
end
private
 def bid_log_params
params.require(:bid_log).permit(:amount, :player_id)
end
end

Now the basic coding part is done.Next step is to configure Faye.Faye needs to run on a separate web server from the web application itself; to accomplish this, you need to create a Rackup config file. Add a faye.ru file to the root of the project and make sure it looks like this

require ‘faye’
bayeux = Faye::RackAdapter.new(:mount => ‘/faye’, :timeout => 25)
bayeux.listen(9292)

This file simply tells Rackup how to start the Faye server. Try it out to ensure that it’s working correctly. Run this in your Terminal:

rackup faye.ru -E production -s thin

Now we are good to go. The application can be run now by starting the rails server. The code associated with this blog can be found at

https://github.com/amkurian/AuctionManager-Sample-Bidding-App