HTTP Protocol, WebSockets and ActionCable — What, How, Why?

HTTP Protocol

HTTP is a request-response protocol. Client (browser) wants something, sends a request to a server and server gives it back to a client.

How does HTTP protocol work?

User => request(‘GET’, ‘POST) to server => server receives the requests and sends a response

WebSockets

WebSockets are a protocol, like HTTP. The difference between WebSockets and HTTP is that WebSockets maintain a persistent connection between the client and server. That mean when the first time connection is going to open, client sent HTTP request to tell server saying “That is not HTTP request, please upgrade to websocket protocol”.

Before WebSockets, the only method for Javascript applications to interact with a server was through XmlHttpRequest. But these have a major disadvantage: The server can't send data unless the client has explicitly requested it. But the new WebSocket feature allows the server to send data whenever it wants.

How do WebSockets work?

What about Action Cable?

ActionCable seamlessly integrates WebSockets with the rest of your Rails application.

Action Cable allows you to not only pass data to your backend, as you normally would but also to broadcast that new data to any other users subscribed to your channel (and room) and have that new data render changes on the other subscribers’ DOMs, without triggering a page refresh.

Setting up ActionCable between a Rails backend and a React front end requires changes in both ends:

BackEnd broadcasts data => subscribed channels receive the data over the ActionCable

class GuessesController < ApplicationController
def create
guess = Guess.new(guess_params)
room = Room.find(guess_params[:room_id])
if guess.save
serialized_data = ActiveModelSerializers::Adapter::Json.new(
GuessSerializer.new(guess)
).serializable_hash
GuessesChannel.broadcast_to room, serialized_data
head :ok
end
end
private
def guess_params
params.require(:guess).permit(:value, :room_id, :user_id, :color, :lucky)
end
end
//channel - 
class GuessesChannel < ApplicationCable::Channel
def subscribed
room = Room.find(params[:room])
stream_for room
end

def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end

The front end: you will need to set up Components that can receive incoming data broadcast over the Action Cable, as well as callback functions to handle that incoming data.

Room selection:

render = () => {
const { rooms, activeRoom } = this.state;
return <div className="roomsList">
<ActionCable channel={{ channel: "RoomsChannel" }} onReceived={this.handleReceivedRoom} />
import React, { Fragment } from 'react'
import { ActionCable } from 'react-actioncable-provider'
const Cable = ({ rooms, handleReceivedGuess }) => {
return (
<Fragment>
{rooms.map(room => {
return (
<ActionCable
key={room.id}
channel={{
channel: "GuessesChannel",
room: room.id
}}
onReceived={handleReceivedGuess}
/>
);
})}
</Fragment>
);
};
export default Cable