CSC/ECE 517 Spring 2015/ch1a 12 LS
Live Streaming
Introduction
The purpose of live streaming is to send data over the Internet in real-time. This requires a data source, a data encoder, a media publisher and a proper network. The concept of streaming first appeared in Rails 3.1, and became more optimus with the publish of Rails 4. Now Rails 4 supports live streaming using handling I/O object and can send data from server to client in real-time.
Background
Template streaming
Streaming module has been added to ActionController since Rail 3.1. In a traditional Rails client-side profile is like this:
This is because that layouts are rendered before the content of the page. The control flow must thus be altered to render the page in the order the client needs to receive it - layout first.
But for some resources which are static, If they could be loaded while waiting for the server response, it would save lots of time.
The module Streaming inverts the regular Rails process of rendering the layout and template. Using streaming, Rails could render template first and then the layout. it first runs method yield and loads up the template, then renders the assets and layouts.
So the profile with streaming is like this:
When to use streaming(*)
It might not be that efficient to use streaming for actions new or edit. But for expensive actions like database query and generation of large amount of data, streaming can be an extremely important and effective. Take the following action as an example:
def storyboard @stories = Story.all @developers = Page.all @comments = Comment.all end
Since most of the queries here are executing in the controller, it might take a while before them to finish, thus causing the front end (user) to wait for long. We can solve this problem and enhance user experience, the above code can be rewrite as follows,
def storyboard # Allow lazy execution of the queries @stories = Story.all @developers = Page.all @comments = Comment.all render :stream => true end
(Note: :Streaming only works with templates. It doesn’t work with :json or :xml)
Communication between layout and template(*)
When streaming, rendering happens top-down instead of inside-out. Rails starts with the layout, and the template is rendered later, when its yield is reached. This means that, if your application currently relies on instance variables set in the template to be used in the layout, they won’t work once you move to streaming. The proper way to communicate between layout and template, regardless of whether you use streaming or not, is by using content_for, provide and yield. Take a simple example where the layout expects the template to tell which title to use:
<html> <head><title><%= yield :title %></title></head> <body><%= yield %></body> </html>
You would use content_for in your template to specify the title:
<%= content_for :title, "Main" %> Hello
And the final result would be:
<html> <head><title>Main</title></head> <body>Hello</body> </html>
However, if content_for is called several times, the final result would have all calls concatenated. For instance, if we have the following template:
<%= content_for :title, "Main" %> Hello <%= content_for :title, " page" %>
The final result would be:
<html> <head><title>Main page</title></head> <body>Hello</body> </html>
This means that, if you have yield :title in your layout and you want to use streaming, you would have to render the whole template (and eventually trigger all queries) before streaming the title and all assets, which kills the purpose of streaming. For this reason Rails 3.1 introduces a new helper called provide that does the same as content_for but tells the layout to stop searching for other entries and continue rendering.
For instance, the template above using provide would be:
<%= provide :title, "Main" %> Hello <%= content_for :title, " page" %>
Giving:
<html> <head><title>Main</title></head> <body>Hello</body> </html>
That said, when streaming, you need to properly check your templates and choose when to use provide and content_for