When Rails introduced remote:true option for links (AJAX requests) I changed my view on how to handle javascript on my websites. I’m playing with streaming in Rails 4.1 (ActionController::Live) and I realized that a similar solution is needed for handling server events (EventSource).
Case:
My website displays a list of tweets (http://localhost:3000/tweets). Every X seconds a new post is added to the list.
Solution:
Let’s forget about live updates for a moment and imagine I would add a form above the list where I could write a tweet and post it to the server (POST /tweets) with <form … remote:true>. In this case the create.js action view will execute a javascript code (that I would define) for adding a new tweet to the list (as described here: Contributing to Ruby on Rails — Ruby on Rails Guides). The logic for live updates should be very similar. The “only difference” in this case is that the create.js action is executed multiple times without refreshing the page.
I built the server events logic similar to railscasts episode 401. When a new tweet is created send the create.js code to $redis channel, the content is sent to a client over /server_events controller-action and the code is evaluate with jquery.
SERVER
GET /server_events
def server_events
response.headers[“Content-Type”] = “text/event-stream”
redis = Redis.new
redis.psubscribe(“tweets.create”) do |on|
on.pmessage do |pattern, event, data|
response.stream.write("id: #{Time.now.to_i}\n")
response.stream.write("event: #{event}\n")
response.stream.write("data: #{data}\n\n")
end
end
rescue IOError
logger.info "Stream closed"
ensure
redis.quit
response.stream.close
end
POST /tweets
def create
…
$redis.publish(“tweets.create”, render_to_string(“tweets/create.js”, layout: false, item: @tweet).to_json)
…
end
CLIENT
sse = new EventSource(‘/server_events’)
sse.addEventListener ‘tweets.create’, (e) →
$.globalEval($.parseJSON(e.data))
What do you think? Suggestions?