asynchronous responses in ruby on rails 4 using sse

ayathustring picture ayathustring · Feb 13, 2014 · Viewed 8.2k times · Source

I want to use server sent events in rails 4. I have read this great article about it. Nevertheless it does not mention how to use in a way that you can set callbacks fired when an event occurs. I need to be able to push to clients over SSE connections as soon as a change was made in a model. I would like to push those changes to any user whom I have an open SSE connection with. Basically I need to know how to do asynchronous event calls in rails 4. Moreover is it easy to accomplish such a task if not what other choices do I have to get it done? let's say for a real time chat application.

Answer

Richard Peck picture Richard Peck · Feb 14, 2014

You'll have to use ActionController::Live within Rails, or something like Pusher if you're comfortable using a third party application:

Tutorial

There is a very good tutorial here


Details

Creating "live" functionality is more of a "bolt-on" than a native feature-set to Rails

You basically have to connect to the server's "channel" via Javascript, and Rails will keep sending updates to that channel

The problem is Rails normally deals with HTTP requests (you send a request, Rails serves a response). This presents a problem to Rails, as asynchronicity is not in its core design paradigm

The live connectivity you experience with SEE's or Websockets isn't live at all - it's just a perpetual connection. ActionController::Live allows Rails to render requests above the standard "HTTP" request structure


How It Works

I see live functionality as "perpetual ajax"

Like "standard" ajax, you send requests directly from your rendered page (nothing special). And like "standard" ajax, you also need to handle the returned data with a client-side engine (Javascript)

The difference is unlike "standard" ajax, "live" functionality can be initiated by the server (hence why SEE's are relatively prominent):

class MessagingController < ApplicationController
  include ActionController::Live

  def send_message
    response.headers['Content-Type'] = 'text/event-stream'
    10.times {
      response.stream.write "This is a test Messagen"
      sleep 1
    }
    response.stream.close
  end
end

This means everyone who's connected to the server's "channel" receives the update (rather than just the individual receiving the update in Ajax)


Channels

The way to create "private" live functionality, you basically need to use "channels"

These allow you to send data to specific individuals (for private messaging etc), allowing you to create a much richer experience