Ruby

WebSockets in Rails 4

I previously published this article on my personal blog early 2013, but thought I’d share it today with our Codeship readers. Enjoy!

I’ve been using Rails 4 (beta) a lot recently. In a previous post we looked at how ActionController::Live can be used with Server-Sent Events, but the problem with that is that there’s no way for the client to communicate back to the web server. Enter: WebSockets.

The main issue with implementing WebSockets is that they have to keep their connections open for a long period of time, and when you’re only running a small cluster of Rails servers, it eats up potential connections fast. That’s why I was excited to hear about two important developments: concurrency in Rails 4 and Rack Hijack.

Concurrency in Rails 4

Rails 4 is now full concurrent, which means that there is no full-stack lock on a request. That means that if you use a concurrent server like Puma you can handle many requests at a time with a single process.

Even better, you can use ruby Threads inside your Rails app. That’s how ActionController::Live works (for streaming).

What this means for us is that we can use Threads to hold websocket connections open without bogging down our server.

Also, this means that our solution does not use Eventmachine, nor does it implement a reactor in any way. It’s concurrent.

Rack Hijack

Rack Hijack came with Rack 1.5.0 which was released in January 2013. Rack hijack allows you to access the underlying socket of a Rack connection in order to bidirectionally communicate with the client. Since Rails is built on Rack we can grab a handle to the client socket right from a Rails controller.

Tubesock

Tubesock is the gem that I made to encapsulate this functionality. It’s very small and new and untested so caveat emptor and all that. At its core it provides a module for Rails controllers and a wrapper method to hijack the rack connection. Then it wraps the ruby gem websocket to handle WebSocket handshakes and frames. Here’s an example of using it in a controller:

class ChatController < ApplicationController
  include Tubesock::Hijack

  def chat
    hijack do |tubesock|
      tubesock.onopen do
        tubesock.send_data "Hello, friend"
      end

      tubesock.onmessage do |data|
        tubesock.send_data message: "You said: #{data}"
      end
    end
  end
end

Right inside the controller action we can hijack the connection and then use some blocks to send information.

You can check out the Tubesock gem on Github for more information.

Also, there is an example chat application you can run and play with.

Happy hacking!

Reference: WebSockets in Rails 4 from our WCG partner Florian Motlik at the Codeship Blog blog.

Nick Gauthier

Nick likes creating for the web, making things fast, and playing strategy games.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button