# frozen_string_literal: true module ActionController # :nodoc: # = Action Controller \Streaming # # Allows views to be streamed back to the client as they are rendered. # # By default, \Rails renders views by first rendering the template # and then the layout. The response is sent to the client 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 # subsequently 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, enabling JavaScripts and stylesheets to be loaded # earlier than usual. # # Several Rack middlewares may not work and you need to be careful when streaming. # This is covered in more detail below, see the Streaming@Middlewares section. # # \Streaming can be added to a given template easily, all you need to do is # to pass the +:stream+ option to +render+. # # class PostsController # def index # @posts = Post.all # render stream: true # end # end # # == When to use streaming # # \Streaming may be considered to be overkill for lightweight actions like # +new+ or +edit+. The real benefit of streaming is on expensive actions # that, for example, do 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 # from streaming you would want to rewrite it as: # # def dashboard # # Allow lazy execution of the queries # @posts = Post.all # @pages = Page.all # @articles = Article.all # render stream: true # end # # Notice that +:stream+ only works with templates. \Rendering +:json+ # or +:xml+ with +:stream+ won't work. # # == 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: # # #
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 defeats the purpose of streaming. Alternatively, you can use
# 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 above using +provide+ would be:
#
# <%= provide :title, "Main" %>
# Hello
# <%= content_for :title, " page" %>
#
# Resulting in:
#
#
#