provide a request and response to all controllers
Controllers should always have a request and response when responding.
Since we make this The Rule(tm), then controllers don't need to be
somewhere in limbo between "asking a response object for a rack
response" or "I, myself contain a rack response". This duality leads to
conditionals spread through the codebase that we can delete:
* 85a78d9358/actionpack/lib/action_controller/metal.rb (L221-L223)
This commit is contained in:
parent
85a78d9358
commit
51c7ac142d
@ -132,6 +132,12 @@ def self.controller_name
|
|||||||
@controller_name ||= name.demodulize.sub(/Controller$/, '').underscore
|
@controller_name ||= name.demodulize.sub(/Controller$/, '').underscore
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.make_response!(request)
|
||||||
|
ActionDispatch::Response.new.tap do |res|
|
||||||
|
res.request = request
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Delegates to the class' <tt>controller_name</tt>
|
# Delegates to the class' <tt>controller_name</tt>
|
||||||
def controller_name
|
def controller_name
|
||||||
self.class.controller_name
|
self.class.controller_name
|
||||||
@ -143,11 +149,10 @@ def controller_name
|
|||||||
# and response object available. You might wish to control the
|
# and response object available. You might wish to control the
|
||||||
# environment and response manually for performance reasons.
|
# environment and response manually for performance reasons.
|
||||||
|
|
||||||
attr_internal :headers, :response, :request
|
attr_internal :response, :request
|
||||||
delegate :session, :to => "@_request"
|
delegate :session, :headers, :to => "@_request"
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@_headers = {"Content-Type" => "text/html"}
|
|
||||||
@_status = 200
|
@_status = 200
|
||||||
@_request = nil
|
@_request = nil
|
||||||
@_response = nil
|
@_response = nil
|
||||||
@ -168,7 +173,7 @@ def params=(val)
|
|||||||
# in Renderer and Redirector.
|
# in Renderer and Redirector.
|
||||||
|
|
||||||
def content_type=(type)
|
def content_type=(type)
|
||||||
headers["Content-Type"] = type.to_s
|
response.content_type = type
|
||||||
end
|
end
|
||||||
|
|
||||||
def content_type
|
def content_type
|
||||||
@ -199,6 +204,7 @@ def status=(status)
|
|||||||
|
|
||||||
def response_body=(body)
|
def response_body=(body)
|
||||||
body = [body] unless body.nil? || body.respond_to?(:each)
|
body = [body] unless body.nil? || body.respond_to?(:each)
|
||||||
|
response.body = body
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -207,12 +213,17 @@ def performed?
|
|||||||
response_body || (response && response.committed?)
|
response_body || (response && response.committed?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def dispatch(name, request) #:nodoc:
|
def dispatch(name, request, response) #:nodoc:
|
||||||
set_request!(request)
|
set_request!(request)
|
||||||
|
set_response!(response)
|
||||||
process(name)
|
process(name)
|
||||||
to_a
|
to_a
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_response!(response) # :nodoc:
|
||||||
|
@_response = response
|
||||||
|
end
|
||||||
|
|
||||||
def set_request!(request) #:nodoc:
|
def set_request!(request) #:nodoc:
|
||||||
@_request = request
|
@_request = request
|
||||||
@_request.controller_instance = self
|
@_request.controller_instance = self
|
||||||
@ -253,20 +264,26 @@ class << self; deprecate :call; end
|
|||||||
def self.action(name)
|
def self.action(name)
|
||||||
if middleware_stack.any?
|
if middleware_stack.any?
|
||||||
middleware_stack.build(name) do |env|
|
middleware_stack.build(name) do |env|
|
||||||
new.dispatch(name, ActionDispatch::Request.new(env))
|
req = ActionDispatch::Request.new(env)
|
||||||
|
res = make_response! req
|
||||||
|
new.dispatch(name, req, res)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
lambda { |env| new.dispatch(name, ActionDispatch::Request.new(env)) }
|
lambda { |env|
|
||||||
|
req = ActionDispatch::Request.new(env)
|
||||||
|
res = make_response! req
|
||||||
|
new.dispatch(name, req, res)
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Direct dispatch to the controller. Instantiates the controller, then
|
# Direct dispatch to the controller. Instantiates the controller, then
|
||||||
# executes the action named +name+.
|
# executes the action named +name+.
|
||||||
def self.dispatch(name, req)
|
def self.dispatch(name, req, res)
|
||||||
if middleware_stack.any?
|
if middleware_stack.any?
|
||||||
middleware_stack.build(name) { |env| new.dispatch(name, req) }.call req.env
|
middleware_stack.build(name) { |env| new.dispatch(name, req, res) }.call req.env
|
||||||
else
|
else
|
||||||
new.dispatch(name, req)
|
new.dispatch(name, req, res)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -36,6 +36,8 @@ def head(status, options = {})
|
|||||||
headers[key.to_s.dasherize.split('-').each { |v| v[0] = v[0].chr.upcase }.join('-')] = value.to_s
|
headers[key.to_s.dasherize.split('-').each { |v| v[0] = v[0].chr.upcase }.join('-')] = value.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
response.status = Rack::Utils.status_code(status)
|
||||||
|
|
||||||
self.status = status
|
self.status = status
|
||||||
self.location = url_for(location) if location
|
self.location = url_for(location) if location
|
||||||
|
|
||||||
@ -44,9 +46,6 @@ def head(status, options = {})
|
|||||||
if include_content?(self.response_code)
|
if include_content?(self.response_code)
|
||||||
self.content_type = content_type || (Mime[formats.first] if formats)
|
self.content_type = content_type || (Mime[formats.first] if formats)
|
||||||
self.response.charset = false if self.response
|
self.response.charset = false if self.response
|
||||||
else
|
|
||||||
headers.delete('Content-Type')
|
|
||||||
headers.delete('Content-Length')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
true
|
true
|
||||||
|
@ -12,17 +12,6 @@ module ClassMethods
|
|||||||
def build_with_env(env = {}) #:nodoc:
|
def build_with_env(env = {}) #:nodoc:
|
||||||
new.tap { |c| c.set_request! ActionDispatch::Request.new(env) }
|
new.tap { |c| c.set_request! ActionDispatch::Request.new(env) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_response!(request)
|
|
||||||
ActionDispatch::Response.new.tap do |res|
|
|
||||||
res.request = request
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_request!(request) #:nodoc:
|
|
||||||
super
|
|
||||||
set_response!(request)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def response_body=(body)
|
def response_body=(body)
|
||||||
@ -33,11 +22,5 @@ def response_body=(body)
|
|||||||
def reset_session
|
def reset_session
|
||||||
@_request.reset_session
|
@_request.reset_session
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def set_response!(request)
|
|
||||||
@_response = self.class.make_response! request
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -65,7 +65,7 @@ class Response
|
|||||||
CONTENT_TYPE = "Content-Type".freeze
|
CONTENT_TYPE = "Content-Type".freeze
|
||||||
SET_COOKIE = "Set-Cookie".freeze
|
SET_COOKIE = "Set-Cookie".freeze
|
||||||
LOCATION = "Location".freeze
|
LOCATION = "Location".freeze
|
||||||
NO_CONTENT_CODES = [204, 304]
|
NO_CONTENT_CODES = [100, 101, 102, 204, 205, 304]
|
||||||
|
|
||||||
cattr_accessor(:default_charset) { "utf-8" }
|
cattr_accessor(:default_charset) { "utf-8" }
|
||||||
cattr_accessor(:default_headers)
|
cattr_accessor(:default_headers)
|
||||||
@ -396,6 +396,7 @@ def rack_response(status, header)
|
|||||||
|
|
||||||
if NO_CONTENT_CODES.include?(@status)
|
if NO_CONTENT_CODES.include?(@status)
|
||||||
header.delete CONTENT_TYPE
|
header.delete CONTENT_TYPE
|
||||||
|
header.delete 'Content-Length'
|
||||||
[status, header, []]
|
[status, header, []]
|
||||||
else
|
else
|
||||||
[status, header, RackBody.new(self)]
|
[status, header, RackBody.new(self)]
|
||||||
|
@ -28,7 +28,9 @@ def dispatcher?; true; end
|
|||||||
|
|
||||||
def serve(req)
|
def serve(req)
|
||||||
params = req.path_parameters
|
params = req.path_parameters
|
||||||
dispatch(controller(req), params[:action], req)
|
controller = controller req
|
||||||
|
res = controller.make_response! req
|
||||||
|
dispatch(controller, params[:action], req, res)
|
||||||
rescue NameError => e
|
rescue NameError => e
|
||||||
if @raise_on_name_error
|
if @raise_on_name_error
|
||||||
raise ActionController::RoutingError, e.message, e.backtrace
|
raise ActionController::RoutingError, e.message, e.backtrace
|
||||||
@ -43,8 +45,8 @@ def controller(req)
|
|||||||
req.controller_class
|
req.controller_class
|
||||||
end
|
end
|
||||||
|
|
||||||
def dispatch(controller, action, req)
|
def dispatch(controller, action, req, res)
|
||||||
controller.dispatch(action, req)
|
controller.dispatch(action, req, res)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -121,12 +121,16 @@ def self.build_app(routes = nil)
|
|||||||
class DeadEndRoutes < ActionDispatch::Routing::RouteSet
|
class DeadEndRoutes < ActionDispatch::Routing::RouteSet
|
||||||
# Stub Rails dispatcher so it does not get controller references and
|
# Stub Rails dispatcher so it does not get controller references and
|
||||||
# simply return the controller#action as Rack::Body.
|
# simply return the controller#action as Rack::Body.
|
||||||
class NullController
|
class NullController < ::ActionController::Metal
|
||||||
def initialize(controller_name)
|
def initialize(controller_name)
|
||||||
@controller = controller_name
|
@controller = controller_name
|
||||||
end
|
end
|
||||||
|
|
||||||
def dispatch(action, req)
|
def make_response!(request)
|
||||||
|
self.class.make_response! request
|
||||||
|
end
|
||||||
|
|
||||||
|
def dispatch(action, req, res)
|
||||||
[200, {'Content-Type' => 'text/html'}, ["#{@controller}##{action}"]]
|
[200, {'Content-Type' => 'text/html'}, ["#{@controller}##{action}"]]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -93,6 +93,8 @@ def test_no_deprecation_when_action_view_record_identifier_is_included
|
|||||||
class ControllerInstanceTests < ActiveSupport::TestCase
|
class ControllerInstanceTests < ActiveSupport::TestCase
|
||||||
def setup
|
def setup
|
||||||
@empty = EmptyController.new
|
@empty = EmptyController.new
|
||||||
|
@empty.set_request!(ActionDispatch::Request.new({}))
|
||||||
|
@empty.set_response!(EmptyController.make_response!(@empty.request))
|
||||||
@contained = Submodule::ContainedEmptyController.new
|
@contained = Submodule::ContainedEmptyController.new
|
||||||
@empty_controllers = [@empty, @contained]
|
@empty_controllers = [@empty, @contained]
|
||||||
end
|
end
|
||||||
|
@ -28,6 +28,8 @@ class BareTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
test "response_body value is wrapped in an array when the value is a String" do
|
test "response_body value is wrapped in an array when the value is a String" do
|
||||||
controller = BareController.new
|
controller = BareController.new
|
||||||
|
controller.set_request!(ActionDispatch::Request.new({}))
|
||||||
|
controller.set_response!(BareController.make_response!(controller.request))
|
||||||
controller.index
|
controller.index
|
||||||
assert_equal ["Hello world"], controller.response_body
|
assert_equal ["Hello world"], controller.response_body
|
||||||
end
|
end
|
||||||
|
@ -179,7 +179,7 @@ class RenderHtmlTest < Rack::TestCase
|
|||||||
|
|
||||||
test "rendering from minimal controller returns response with text/html content type" do
|
test "rendering from minimal controller returns response with text/html content type" do
|
||||||
get "/render_html/minimal/index"
|
get "/render_html/minimal/index"
|
||||||
assert_content_type "text/html"
|
assert_content_type "text/html; charset=utf-8"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "rendering from normal controller returns response with text/html content type" do
|
test "rendering from normal controller returns response with text/html content type" do
|
||||||
|
@ -157,7 +157,7 @@ class RenderPlainTest < Rack::TestCase
|
|||||||
|
|
||||||
test "rendering from minimal controller returns response with text/plain content type" do
|
test "rendering from minimal controller returns response with text/plain content type" do
|
||||||
get "/render_plain/minimal/index"
|
get "/render_plain/minimal/index"
|
||||||
assert_content_type "text/plain"
|
assert_content_type "text/plain; charset=utf-8"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "rendering from normal controller returns response with text/plain content type" do
|
test "rendering from normal controller returns response with text/plain content type" do
|
||||||
|
Loading…
Reference in New Issue
Block a user