Permalink
Browse files

Reduce the cost of using ActionController::Http significantly by:

  * Removing the dependency on AD::Request and AD::Response
  * Moving the logic for the request and response object
    into a new module that is included by default.
  * Changing Renderer and Redirector to use self.headers,
    self.content_type, and self.status, which have very basic
    default implementations on AC::Http. When RackConvenience
    is included (which it is by default on AC::Base), the full
    Request/Response logic is used instead of the simple logic.
  • Loading branch information...
1 parent 311d686 commit 6bbe965ccdcef2d7e713e65175722718d325b2bd Yehuda Katz committed May 27, 2009
@@ -4,6 +4,7 @@ module ActionController
autoload :HideActions, "action_controller/new_base/hide_actions"
autoload :Http, "action_controller/new_base/http"
autoload :Layouts, "action_controller/new_base/layouts"
+ autoload :RackConvenience, "action_controller/new_base/rack_convenience"
autoload :Rails2Compatibility, "action_controller/new_base/compatibility"
autoload :Redirector, "action_controller/new_base/redirector"
autoload :Renderer, "action_controller/new_base/renderer"
@@ -14,6 +14,7 @@ class Base < Http
include ActionController::Renderers::All
include ActionController::Layouts
include ActionController::ConditionalGet
+ include ActionController::RackConvenience
# Legacy modules
include SessionManagement
@@ -1,5 +1,8 @@
module ActionController
module ConditionalGet
+ extend ActiveSupport::DependencyModule
+
+ depends_on RackConvenience
# Sets the etag, last_modified, or both on the response and renders a
# "304 Not Modified" response if the request is already fresh.
@@ -6,7 +6,7 @@ class Http < AbstractController::Base
abstract!
# :api: public
- attr_internal :request, :response, :params
+ attr_internal :params, :env
# :api: public
def self.controller_name
@@ -36,32 +36,48 @@ def self.call(env)
controller.call(env).to_rack
end
- delegate :headers, :to => "@_response"
+ # The details below can be overridden to support a specific
+ # Request and Response object. The default ActionController::Base
+ # implementation includes RackConvenience, which makes a request
+ # and response object available. You might wish to control the
+ # environment and response manually for performance reasons.
- def params
- @_params ||= @_request.parameters
+ attr_internal :status, :headers, :content_type
+
+ def initialize(*)
+ @_headers = {}
+ super
+ end
+
+ # Basic implements for content_type=, location=, and headers are
+ # provided to reduce the dependency on the RackConvenience module
+ # in Renderer and Redirector.
+
+ def content_type=(type)
+ headers["Content-Type"] = type.to_s
+ end
+
+ def location=(url)
+ headers["Location"] = url
end
# :api: private
def call(name, env)
- @_request = ActionDispatch::Request.new(env)
- @_response = ActionDispatch::Response.new
- @_response.request = request
+ @_env = env
process(name)
to_rack
end
+ # :api: private
+ def to_rack
+ [status, headers, response_body]
+ end
+
def self.action(name)
@actions ||= {}
@actions[name.to_s] ||= proc do |env|
new.call(name, env)
end
end
-
- # :api: private
- def to_rack
- @_response.prepare!
- @_response.to_a
- end
end
end
@@ -0,0 +1,34 @@
+module ActionController
+ module RackConvenience
+ extend ActiveSupport::DependencyModule
+
+ included do
+ delegate :headers, :status=, :location=,
+ :status, :location, :content_type, :to => "@_response"
+ attr_internal :request, :response
+ end
+
+ def call(name, env)
+ @_request = ActionDispatch::Request.new(env)
+ @_response = ActionDispatch::Response.new
+ @_response.request = request
+ super
+ end
+
+ def params
+ @_params ||= @_request.parameters
+ end
+
+ # :api: private
+ def to_rack
+ @_response.prepare!
+ @_response.to_a
+ end
+
+ def response_body=(body)
+ response.body = body if response
+ super
+ end
+
+ end
+end
@@ -11,8 +11,8 @@ module Redirector
def redirect_to(url, status) #:doc:
raise AbstractController::DoubleRenderError if response_body
logger.info("Redirected to #{url}") if logger && logger.info?
- response.status = status
- response.location = url.gsub(/[\r\n]/, '')
+ self.status = status
+ self.location = url.gsub(/[\r\n]/, '')
self.response_body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>"
end
end
@@ -57,7 +57,7 @@ module Json
def _render_json(json, options)
json = ActiveSupport::JSON.encode(json) unless json.respond_to?(:to_str)
json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
- response.content_type ||= Mime::JSON
+ self.content_type ||= Mime::JSON
self.response_body = json
end
end
@@ -67,7 +67,7 @@ module Js
register_renderer :js
def _render_js(js, options)
- response.content_type ||= Mime::JS
+ self.content_type ||= Mime::JS
self.response_body = js
end
end
@@ -77,7 +77,7 @@ module Xml
register_renderer :xml
def _render_xml(xml, options)
- response.content_type ||= Mime::XML
+ self.content_type ||= Mime::XML
self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml
end
end
@@ -88,7 +88,7 @@ module Rjs
def _render_update(proc, options)
generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(_action_view, &proc)
- response.content_type = Mime::JS
+ self.content_type = Mime::JS
self.response_body = generator.to_s
end
end
@@ -8,16 +8,11 @@ def process_action(*)
self.formats = request.formats.map {|x| x.to_sym}
super
end
-
- def response_body=(body)
- response.body = body if response
- super
- end
def render(options)
super
options[:_template] ||= _action_view._partial
- response.content_type ||= begin
+ self.content_type ||= begin
mime = options[:_template].mime_type
formats.include?(mime && mime.to_sym) || formats.include?(:all) ? mime : Mime::Type.lookup_by_extension(formats.first)
end
@@ -76,9 +71,9 @@ def _render_partial(partial, options)
def _process_options(options)
status, content_type, location = options.values_at(:status, :content_type, :location)
- response.status = status if status
- response.content_type = content_type if content_type
- response.headers["Location"] = url_for(location) if location
+ self.status = status if status
+ self.content_type = content_type if content_type
+ self.headers["Location"] = url_for(location) if location
end
end
end
@@ -1,5 +1,9 @@
module ActionController
module Session
+ extend ActiveSupport::DependencyModule
+
+ depends_on RackConvenience
+
def session
@_request.session
end
@@ -2,6 +2,8 @@ module ActionController
module Testing
extend ActiveSupport::DependencyModule
+ depends_on RackConvenience
+
# OMG MEGA HAX
def process_with_new_base_test(request, response)
@_request = request
@@ -1,5 +1,9 @@
module ActionController
module UrlFor
+ extend ActiveSupport::DependencyModule
+
+ depends_on RackConvenience
+
def process_action(*)
initialize_current_url
super

0 comments on commit 6bbe965

Please sign in to comment.