What are websockets
Tags: rails, actioncable, react, websockets
Published: 2019-05-14 18:50:55

---
title: What are websockets
published: true
description: What a websocket is and a simple implementation using Ruby on rails, React, and Actioncable
tags: rails, actioncable, react, websockets
---

A web socket is a computer communications protocol that provides full-duplex communication channels over a single TCP connection. TCP stands for Transmission Control Protocol and is one of the main communication protocols in the [internet protocol suite](https://en.wikipedia.org/wiki/Internet_protocol_suite).  Establishing a full-duplex communication is the the power of the web socket.  

What is Full-duplex communication? Picture a section of road with a post office on either end (A and B) that is 1 lane wide. Cars can go in either direction, BUT can only go when they are told it’s all clear by the other side or they may get in a head on collision (also, if they go even slightly off road they explode into a million shiny pieces).  So, a car leaves A and travels towards B, and B knows not to go until the car from A reaches B and says the road is clear.  Car A may have a request that something be sent back to post office A, and/or it may be communicating some info by dropping off some mail. 

![alt text](https://www.dangerousroads.org/images/stories/__Roads00000e/BigKahekili%20Highway0.jpg "One Lane Road")

This happens a lot with web communication. Client sends a request and/or info, server gets the request/info, processes what to do with it and sends back some info. Turns are taken, my kindergarten teacher, Mrs. Smith, is happy and all is well in the world. But web sockets throw all that polite turn taking out the window.

We’ve picture a single lane road as standard communication where two entities communicate by taking turns sending requests and information. But, and I know this is crazy, what if there was a TWO lane road. What if there was a world where 2 entities could send information whenever they wanted, AND, could receive information whenever the other felt like sending it.  This bi-directional  road means that each side doesn’t have to send out requests because there is no  need  to control who’s turn it is, an entity simply needs to “subscribe” to the other to accept any information that may come from that direction.

![alt text](https://i.pinimg.com/originals/39/3a/81/393a813c18c76da08c22efc0c6086413.jpg "Two Lane Road")

Ok, another thought experiment. Entity A is a server that performs some function and returns an answer. However, this time there isn’t just  entity B as a client, there are hundreds of clients and they all have this 2 lane road leading to/from the server. The server can now  update all the clients without the need for request/response from each individual client. The server can simply “broadcast” some information to all the clients “subscribed” to that lane (or channel) at the same time and each client can send information to the server for processing.  

Cool! No more polling or long-polling for a client to try to stay current with the state of the server.  Information is now realtime, being sent by both sides upon processing, and received whenever it comes at them.  We now live in a turn free world where things just do as they please.  Now we can do cool things like make multiplayer realtime games!

To dip a little into web sockets, I made a 2 player tic-tac-toe game that used them.  Ruby on rails and Action cable provide a pretty straight forward implementation of web sockets for beginners.  Here is a some basic setup to get you started with Ruby and Actioncable with a React frontend to use websockets. 

First generate your React front end by entering the following into your console:
`
create-react-app <your-frontend-project-name>
cd <your-frontend-project-name>
yarn add actioncable
yarn start
`
And then get you rails backend wireframe up by entering the following into your console:
`
rails new <your-backend-project-name> --api
cd <your-backend-project-name>
rails g scaffold <your-model-name> <your-models-attributes>
rails db:migrate
`
The next step is to persist an instance of your model by creating one in the rials console:
`
rails c 
<your-model>.create!(attributes)
`
Be sure to setup cors by uncommenting the 'rack-cors' gem in your gemfile and uncommenting the following in your application.rb. Making sure origins is set to the acceptable url, or in this case I used * to make every url acceptable.
```ruby
config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins '*'
        resource '*', :headers => :any, :methods => [:get, :post, :options]
      end
    end
```

Run Bundle install.

Now to wire up actioncable. The next few steps are fairly simple. Navigate to your `config.routes.rb` and add the following before the last `end`.
`
mount ActionCable.server => '/cable'
`
Then, go to your console and type in the following:
`
rails g channel <your-model-name>
`

Now Actioncable can pickup websockets that are coming into `/cable` and your rails backend will have a new file `app/channels/<your-model>_channel.rb`

Open that file up.
```ruby
class <your-model>Channel < ApplicationCable::Channel
  def subscribed
    # stream_from "some_channel"
    stream_from '<your-model>'
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def receive(data)
    <your-model> = <Your-Model>.find(data["id"])
    <your-model>.update!(attr: data["attr"])
    ActionCable.server.broadcast('<your-model>', data)
  end
end
```

Here, we've added `stream_from` to the subscribed method and then told rails what to do with received data in the receive method. Our backend is  now setup for streaming!

![alt text](https://media0.giphy.com/media/2csuIJj6TmuKA/giphy.webp?cid=790b76115cdb073431614a326f5eedb6&rid=giphy.webp "cool stream")

Now, lets setup our frontend to subscribe and talk to our backend.  We will need to do a few things in order to accomplish this.  First, connect to `/cable` that we setup in our backend. Second, subscribe to the our model channel. And last, send any data by the user on the front side.

To accomplish these 3 things we must first import actioncable by putting `import ActionCable from 'actioncable'` at the top of your app.js and creating a consumer inside of your componentDidMount method. We must next setup our subscription and set a callback for when we receive data. The final file might look something like:
```javascript
import React, { Component } from 'react'
import './App.css'
import ActionCable from 'actioncable'

class App extends Component {
  state = { <your-state>: undefined }

  componentDidMount() {
    window.fetch('http://localhost:3001/<your-model>/1').then(data => {
      data.json().then(res => {
        this.setState({ <your-state>: res.<model-attribute> })
      })
    })

    const cable = ActionCable.createConsumer('ws://localhost:3001/cable')
    this.sub = cable.subscriptions.create('NotesChannel', {
      received: this.handleReceiveNewText
    })
  }

  handleReceiveNewData = ({ <model-attribute> }) => {
    if (<model-attribute> !== this.state.<your-state>) {
      this.setState({ <model-attribute> })
    }
  }

  handleChange = e => {
    this.setState({ <your-state>: e.target.value })
    this.sub.send({ <your-state>: e.target.value, id: 1 })
  }
```

That pretty much the gist of setting up a websocket with rails and react. There is obviously some more things that need to be done like displaying/grabbing information on the screen (controlled inputs are best), data sanitization, authorization, and more. But, this is a super simple setup to get you started.