Using EventSource as remote:true

45 views
Skip to first unread message

Xpepermint

unread,
Apr 1, 2014, 5:21:32 PM4/1/14
to rubyonra...@googlegroups.com
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: http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#reporting-an-issue). 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?

Steve Schwartz

unread,
Apr 1, 2014, 11:01:19 PM4/1/14
to rubyonra...@googlegroups.com
I'm not clear what you're proposing to add to Rails. Remote requests do 2 things:

1) Send request to server via XHR, and 
2) Receive (and possibly run) response from the server.

The remote helpers in Rails just hook up DOM elements, links and forms, to trigger (1), which will then trigger (2). Server-sent events are basically just (2), but without the need to be triggered by (1). Because (1) isn't needed with SSE (or EventSource on the JavaScript side), there's not as tangible a need for similar Rails view helpers that I can see.

From your example, it seems like you're just trying to publish some JSON from a template from SSE. Instead of rendering a JS file to string and then coercing that to JSON, couldn't you instead render a json.erb template file?

That said, I'm not extremely familiar with redis publish/psubscribe, so maybe I'm misunderstanding what you're proposing.

-- Steve Schwartz

--
You received this message because you are subscribed to the Google Groups "Ruby on Rails: Core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-co...@googlegroups.com.
To post to this group, send email to rubyonra...@googlegroups.com.
Visit this group at http://groups.google.com/group/rubyonrails-core.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages