aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller/metal/streaming.rb
diff options
context:
space:
mode:
authorJosé Valim <jose.valim@gmail.com>2011-05-01 14:50:42 +0200
committerJosé Valim <jose.valim@gmail.com>2011-05-01 14:50:42 +0200
commit8dbee3aba6920edcae20abf3af7f803e528f9ee0 (patch)
treebe75f9a64d6183f26b3bf752c4ba17533fa00e26 /actionpack/lib/action_controller/metal/streaming.rb
parent46611a995d91abf7bb2a64c62af13b6449c75b07 (diff)
downloadrails-8dbee3aba6920edcae20abf3af7f803e528f9ee0.tar.gz
rails-8dbee3aba6920edcae20abf3af7f803e528f9ee0.tar.bz2
rails-8dbee3aba6920edcae20abf3af7f803e528f9ee0.zip
Streaming docs.
Diffstat (limited to 'actionpack/lib/action_controller/metal/streaming.rb')
-rw-r--r--actionpack/lib/action_controller/metal/streaming.rb202
1 files changed, 201 insertions, 1 deletions
diff --git a/actionpack/lib/action_controller/metal/streaming.rb b/actionpack/lib/action_controller/metal/streaming.rb
index 5b8111f30d..0dd847f967 100644
--- a/actionpack/lib/action_controller/metal/streaming.rb
+++ b/actionpack/lib/action_controller/metal/streaming.rb
@@ -2,7 +2,207 @@ require 'active_support/core_ext/file/path'
require 'rack/chunked'
module ActionController #:nodoc:
- # Methods for sending streaming templates back to the client.
+ # 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:
+ #
+ # <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 <code>yield :title</code> 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:
+ #
+ # <html>
+ # <head><title>Main</title></head>
+ # <body>Hello</body>
+ # </html>
+ #
+ # That said, when streaming, you need to properly check your templates
+ # and chose when to use +provide+ and +content_for+.
+ #
+ # == Headers, cookies, session and flash
+ #
+ # When streaming, the HTTP headers are sent to the client right before
+ # it renders the first line. This means that, modifying headers, cookies,
+ # session or flash after the template start rendering will not propagate
+ # to the client.
+ #
+ # If you try to modify cookies, session or flash, a ClosedError will be
+ # raised, showing those objects are closed for modification.
+ #
+ # == Middlewares
+ #
+ # Middlewares that need to manipulate the body won't work with streaming.
+ # You should disable those middlewares whenever streaming in development
+ # or production. For instance, Rack::Bug won't work when streaming as it
+ # needs to inject contents in the HTML body.
+ #
+ # Also Rack::Cache won't work with streaming as it does not support
+ # streaming bodies yet. So, whenever streaming, Cache-Control is automatically
+ # set to "no-cache".
+ #
+ # == Errors
+ #
+ # When it comes to streaming, exceptions get a bit more complicated. This
+ # happens because part of the template was already rendered and streamed to
+ # the client, making it impossible to render a whole exception page.
+ #
+ # Currently, when an exception happens in development or production, Rails
+ # will automatically stream to the client:
+ #
+ # "><script type="text/javascript">window.location = "/500.html"</script></html>
+ #
+ # The first two characters (">) are required in case the exception happens
+ # while rendering attributes for a given tag. You can check the real cause
+ # for the exception in your logger.
+ #
+ # == Web server support
+ #
+ # Not all web servers support streaming out-of-the-box. You need to check
+ # the instructions for each of them.
+ #
+ # ==== Unicorn
+ #
+ # Unicorn supports streaming but it needs to be configured. For this, you
+ # need to create a config file as follow:
+ #
+ # # unicorn.config.rb
+ # listen 3000, :tcp_nopush => false
+ #
+ # And use it on initialization:
+ #
+ # unicorn_rails --config-file unicorn.config.rb
+ #
+ # You may also want to configure other parameters like :tcp_nodelay. Please
+ # check its documentation for more information: http://unicorn.bogomips.org/Unicorn/Configurator.html#method-i-listen
+ #
+ # If you are using unicorn with nginx, you may need to tweak nginx.
+ # Streaming should work out of the box on Rainbows.
+ #
+ # ==== Passenger
+ #
+ # To be described.
+ #
module Streaming
extend ActiveSupport::Concern