1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Body... wanna *stream* my body? Body... such a thrill my body!

Added stream as class level method to make it explicit when to stream.
Render also accepts :stream as option.
This commit is contained in:
José Valim 2011-04-18 08:52:29 +02:00
parent 7a152ab012
commit 389d15ef13
5 changed files with 122 additions and 0 deletions

View file

@ -31,6 +31,7 @@ module ActionController
autoload :Rescue
autoload :Responder
autoload :SessionManagement
autoload :Streaming
autoload :Testing
autoload :UrlFor
end

View file

@ -199,6 +199,7 @@ module ActionController
Flash,
RequestForgeryProtection,
ForceSSL,
Streaming,
DataStreaming,
RecordIdentifier,
HttpAuthentication::Basic::ControllerMethods,

View file

@ -0,0 +1,57 @@
require 'active_support/core_ext/file/path'
require 'rack/chunked'
module ActionController #:nodoc:
# Methods for sending streaming templates back to the client.
module Streaming
extend ActiveSupport::Concern
include AbstractController::Rendering
attr_internal :stream
module ClassMethods
# Render streaming templates. It accepts :only, :except, :if and :unless as options
# to specify when to stream, as in ActionController filters.
def stream(options={})
if defined?(Fiber)
before_filter :_stream_filter, options
else
raise "You cannot use streaming if Fiber is not available."
end
end
end
protected
# Mark following render calls as streaming.
def _stream_filter #:nodoc:
self.stream = true
end
# Consider the stream option when normalazing options.
def _normalize_options(options) #:nodoc:
super
options[:stream] = self.stream unless options.key?(:stream)
end
# Set proper cache control and transfer encoding when streaming
def _process_options(options) #:nodoc:
super
if options[:stream]
headers["Cache-Control"] ||= "no-cache"
headers["Transfer-Encoding"] = "chunked"
headers.delete("Content-Length")
end
end
# Call render_to_body if we are streaming instead of usual +render+.
def _render_template(options) #:nodoc:
if options.delete(:stream)
Rack::Chunked::Body.new view_context.render_body(options)
else
super
end
end
end
end

View file

@ -2,6 +2,7 @@ module ActionView
module CompiledTemplates #:nodoc:
# holds compiled template code
end
# = Action View Context
#
# Action View contexts are supplied to Action Controller to render template.

View file

@ -0,0 +1,62 @@
require 'abstract_unit'
module RenderStreaming
class BasicController < ActionController::Base
self.view_paths = [ActionView::FixtureResolver.new(
"render_streaming/basic/hello_world.html.erb" => "Hello world",
"layouts/application.html.erb" => "<%= yield %>, I'm here!"
)]
layout "application"
stream :only => :hello_world
def hello_world
end
def explicit
render :action => "hello_world", :stream => true
end
def no_layout
render :action => "hello_world", :stream => true, :layout => false
end
def explicit_cache
headers["Cache-Control"] = "private"
render :action => "hello_world", :stream => true
end
end
class StreamingTest < Rack::TestCase
test "rendering with streaming enabled at the class level" do
get "/render_streaming/basic/hello_world"
assert_body "b\r\nHello world\r\nb\r\n, I'm here!\r\n0\r\n\r\n"
assert_streaming!
end
test "rendering with streaming given to render" do
get "/render_streaming/basic/explicit"
assert_body "b\r\nHello world\r\nb\r\n, I'm here!\r\n0\r\n\r\n"
assert_streaming!
end
test "rendering with streaming do not override explicit cache control given to render" do
get "/render_streaming/basic/explicit_cache"
assert_body "b\r\nHello world\r\nb\r\n, I'm here!\r\n0\r\n\r\n"
assert_streaming! "private"
end
test "rendering with streaming no layout" do
get "/render_streaming/basic/no_layout"
assert_body "b\r\nHello world\r\n0\r\n\r\n"
assert_streaming!
end
def assert_streaming!(cache="no-cache")
assert_status 200
assert_equal nil, headers["Content-Length"]
assert_equal "chunked", headers["Transfer-Encoding"]
assert_equal cache, headers["Cache-Control"]
end
end if defined?(Fiber)
end