require 'active_support/core_ext/file/path' require 'rack/chunked' module ActionController #:nodoc: # Allow views to be streamed back to the client as they are rendered. # # The default way Rails renders views is by first rendering the template # and then the layout. The first chunk of response is sent to the client # just after the whole template is rendered, all queries are made and the # layout is processed. # # Streaming inverts the rendering flow by rendering the layout first and # streaming each part of the layout as they are processed. This allows the # header of the html (which is usually in the layout) to be streamed back # to client very quickly, allowing javascripts and stylesheets to be loaded # earlier than usual. # # This approach was introduced in Rails 3.1 and is still improving. Several # Rack middlewares may not work and you need to be careful when streaming. # Those points are going to be addressed soon. # # In order to use streaming, you will need to use a Ruby version that # supports Fibers (Fibers are supported since version 1.9.2 of the main # Ruby implementation). # # == Examples # # Streaming can be added to a controller easily, all you need to do is # call stream at the controller class: # # class PostsController # stream # end # # The +stream+ method accepts the same options as +before_filter+ and friends: # # class PostsController # stream :only => :index # end # # You can also selectively turn on streaming for specific actions: # # class PostsController # def index # @post = Post.scoped # render :stream => true # end # end # # == When to use streaming # # Streaming may be considering an overkill for common actions like # new or edit. The real benefit of streaming is on expensive actions # that, for example, does a lot of queries on the database. # # In such actions, you want to delay queries execution as much as you can. # For example, imagine the following dashboard action: # # def dashboard # @posts = Post.all # @pages = Page.all # @articles = Article.all # end # # Most of the queries here are happening in the controller. In order to benefit # most of streaming, you would want to rewrite it as: # # def dashboard # # Allow lazily execution of the query # @posts = Post.scoped # @pages = Page.scoped # @articles = Article.scoped # render :stream => true # end # # == Communication between layout and template # # When streaming, the layout is rendered first than the template. # This means that, if your application currently rely on 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 if 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: # # #
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 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 below, using +provide+:
#
# <%= provide :title, "Main" %>
# Hello
# <%= content_for :title, " page" %>
#
# Has as final result:
#
#
#