Shower is a gem for Ruby on Rails 4 that simplifies message streaming, the ability to push data to the front end in real time. ActionController::Live
is a new feature in Rails 4 that allows for message streaming. Essentially, a user opens a persistent connection to a Live controller and messages are pushed through the connection. While instant messaging seems to be the standard ‘Hello World’ introduction to streaming, there are many more uses. For example, inventory notifications for an online store, stock prices, breaking news, maintenance alerts, etc. As message streaming finds more uses, more and more clients will expect to see those features in their sites and applications.
Basic Example
To take advantage of this great technology using Shower, you only need to write 5 lines of code in 3 simple steps.
1. Subscribe to message stream events. In this case, we will listen to the alert.new event, but you can pass an array of as many events as you wish.
stream = new Shower('/stream', ['alert.new'])
2. Define an event to take place when a message is received. In this case, we will simply open a JavaScript alert with the event data.
stream.addEventListener('alert.new', function(event) { return alert(event.data); });
3. Publish an event to the message stream.
Shower::Stream.publish('alert.new', 'Hello World!')
It’s that simple!
JSON Data Example
Let’s look at another quick example which demonstrates the ability to push JSON objects.
1. Subscribe to the message.new event stream.
stream = new Shower('/stream', ['message.new'])
2. When there is a new message, create an alert showing who the message is from and the actual message.
stream.addEventListener('message.new', function(event) { return alert("Message From:" + event.data.username + " - " + event.data.message); });
3. Publish a message.
Shower::Stream.publish('message.new', { username: 'anon', message: 'hello!' })
Controller Breakdown
To explain how this all works, let’s look at the StreamController:
class Shower::StreamController < ApplicationController include ActionController::Live before_action :close_db_connection def index response.headers['Content-Type'] = 'text/event-stream' redis = Redis.new redis.subscribe(params[:events].split(',') << 'heartbeat') do |on| on.message do |event, data| response.stream.write("event: #{event}\n") response.stream.write("data: #{data}\n\n") end end rescue IOError # stream closed ensure # stopping stream thread redis.quit response.stream.close end private def close_db_connection ActiveRecord::Base.connection_pool.release_connection end end
He’s a brief synopsis of what’s going on:
include ActionController::Live
allows us to open the event stream.before_action :close_db_connection
, this will close the current database connection, so we aren’t using up any of our available connections from the database pool. This is especially important once you have few dozen connections open.- At the beginning of the index action, we declare the
text/event-stream
content type headers. This lets the other side know that there are going to be event messages streaming through, so the connection should be left open. - Then we create a new Redis instance and subscribe the user to the their requested events, plus the heartbeat
- The heartbeat is a way of destroying stale connections.
- Then when the redis instance pickups up on any of the subscribed events, we write them to the stream. First the event name is written, then the event data.
- Finally, we ensure that the redis instance is destroyed and the stream is closed.
If you would like to know more about how Shower works, feel free to poke around the repository. If you think it can be improved, fork it and create a pull request.
https://github.com/kpheasey/shower