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
|
||||
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>
|
||||
def controller_name
|
||||
self.class.controller_name
|
||||
@ -143,11 +149,10 @@ def controller_name
|
||||
# and response object available. You might wish to control the
|
||||
# environment and response manually for performance reasons.
|
||||
|
||||
attr_internal :headers, :response, :request
|
||||
delegate :session, :to => "@_request"
|
||||
attr_internal :response, :request
|
||||
delegate :session, :headers, :to => "@_request"
|
||||
|
||||
def initialize
|
||||
@_headers = {"Content-Type" => "text/html"}
|
||||
@_status = 200
|
||||
@_request = nil
|
||||
@_response = nil
|
||||
@ -168,7 +173,7 @@ def params=(val)
|
||||
# in Renderer and Redirector.
|
||||
|
||||
def content_type=(type)
|
||||
headers["Content-Type"] = type.to_s
|
||||
response.content_type = type
|
||||
end
|
||||
|
||||
def content_type
|
||||
@ -199,6 +204,7 @@ def status=(status)
|
||||
|
||||
def response_body=(body)
|
||||
body = [body] unless body.nil? || body.respond_to?(:each)
|
||||
response.body = body
|
||||
super
|
||||
end
|
||||
|
||||
@ -207,12 +213,17 @@ def performed?
|
||||
response_body || (response && response.committed?)
|
||||
end
|
||||
|
||||
def dispatch(name, request) #:nodoc:
|
||||
def dispatch(name, request, response) #:nodoc:
|
||||
set_request!(request)
|
||||
set_response!(response)
|
||||
process(name)
|
||||
to_a
|
||||
end
|
||||
|
||||
def set_response!(response) # :nodoc:
|
||||
@_response = response
|
||||
end
|
||||
|
||||
def set_request!(request) #:nodoc:
|
||||
@_request = request
|
||||
@_request.controller_instance = self
|
||||
@ -253,20 +264,26 @@ class << self; deprecate :call; end
|
||||
def self.action(name)
|
||||
if middleware_stack.any?
|
||||
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
|
||||
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
|
||||
|
||||
# Direct dispatch to the controller. Instantiates the controller, then
|
||||
# executes the action named +name+.
|
||||
def self.dispatch(name, req)
|
||||
def self.dispatch(name, req, res)
|
||||
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
|
||||
new.dispatch(name, req)
|
||||
new.dispatch(name, req, res)
|
||||
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
|
||||
end
|
||||
|
||||
response.status = Rack::Utils.status_code(status)
|
||||
|
||||
self.status = status
|
||||
self.location = url_for(location) if location
|
||||
|
||||
@ -44,9 +46,6 @@ def head(status, options = {})
|
||||
if include_content?(self.response_code)
|
||||
self.content_type = content_type || (Mime[formats.first] if formats)
|
||||
self.response.charset = false if self.response
|
||||
else
|
||||
headers.delete('Content-Type')
|
||||
headers.delete('Content-Length')
|
||||
end
|
||||
|
||||
true
|
||||
|
@ -12,17 +12,6 @@ module ClassMethods
|
||||
def build_with_env(env = {}) #:nodoc:
|
||||
new.tap { |c| c.set_request! ActionDispatch::Request.new(env) }
|
||||
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
|
||||
|
||||
def response_body=(body)
|
||||
@ -33,11 +22,5 @@ def response_body=(body)
|
||||
def reset_session
|
||||
@_request.reset_session
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_response!(request)
|
||||
@_response = self.class.make_response! request
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -65,7 +65,7 @@ class Response
|
||||
CONTENT_TYPE = "Content-Type".freeze
|
||||
SET_COOKIE = "Set-Cookie".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_headers)
|
||||
@ -396,6 +396,7 @@ def rack_response(status, header)
|
||||
|
||||
if NO_CONTENT_CODES.include?(@status)
|
||||
header.delete CONTENT_TYPE
|
||||
header.delete 'Content-Length'
|
||||
[status, header, []]
|
||||
else
|
||||
[status, header, RackBody.new(self)]
|
||||
|
@ -28,7 +28,9 @@ def dispatcher?; true; end
|
||||
|
||||
def serve(req)
|
||||
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
|
||||
if @raise_on_name_error
|
||||
raise ActionController::RoutingError, e.message, e.backtrace
|
||||
@ -43,8 +45,8 @@ def controller(req)
|
||||
req.controller_class
|
||||
end
|
||||
|
||||
def dispatch(controller, action, req)
|
||||
controller.dispatch(action, req)
|
||||
def dispatch(controller, action, req, res)
|
||||
controller.dispatch(action, req, res)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -121,12 +121,16 @@ def self.build_app(routes = nil)
|
||||
class DeadEndRoutes < ActionDispatch::Routing::RouteSet
|
||||
# Stub Rails dispatcher so it does not get controller references and
|
||||
# simply return the controller#action as Rack::Body.
|
||||
class NullController
|
||||
class NullController < ::ActionController::Metal
|
||||
def initialize(controller_name)
|
||||
@controller = controller_name
|
||||
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}"]]
|
||||
end
|
||||
end
|
||||
|
@ -93,6 +93,8 @@ def test_no_deprecation_when_action_view_record_identifier_is_included
|
||||
class ControllerInstanceTests < ActiveSupport::TestCase
|
||||
def setup
|
||||
@empty = EmptyController.new
|
||||
@empty.set_request!(ActionDispatch::Request.new({}))
|
||||
@empty.set_response!(EmptyController.make_response!(@empty.request))
|
||||
@contained = Submodule::ContainedEmptyController.new
|
||||
@empty_controllers = [@empty, @contained]
|
||||
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
|
||||
controller = BareController.new
|
||||
controller.set_request!(ActionDispatch::Request.new({}))
|
||||
controller.set_response!(BareController.make_response!(controller.request))
|
||||
controller.index
|
||||
assert_equal ["Hello world"], controller.response_body
|
||||
end
|
||||
|
@ -179,7 +179,7 @@ class RenderHtmlTest < Rack::TestCase
|
||||
|
||||
test "rendering from minimal controller returns response with text/html content type" do
|
||||
get "/render_html/minimal/index"
|
||||
assert_content_type "text/html"
|
||||
assert_content_type "text/html; charset=utf-8"
|
||||
end
|
||||
|
||||
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
|
||||
get "/render_plain/minimal/index"
|
||||
assert_content_type "text/plain"
|
||||
assert_content_type "text/plain; charset=utf-8"
|
||||
end
|
||||
|
||||
test "rendering from normal controller returns response with text/plain content type" do
|
||||
|
Loading…
Reference in New Issue
Block a user