Permalink
Browse files

Performance speedup for ActionController (closes #4174) [Stefan Kaes]…

… Includes caching of filter chains -- be on the lookout for problems with that!

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3989 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent 324ece2 commit d19e8f412f3cbd32842f94cba11e5c1148dfd558 @dhh dhh committed Mar 20, 2006
@@ -371,13 +371,13 @@ def process(request, response, method = :perform_action, *arguments) #:nodoc:
initialize_template_class(response)
assign_shortcuts(request, response)
initialize_current_url
- action_name(:refresh)
+ assign_names
forget_variables_added_to_assigns
log_processing
send(method, *arguments)
- return response
+ response
ensure
process_cleanup
end
@@ -469,15 +469,6 @@ def controller_name
self.class.controller_name
end
- # Returns the name of the current action
- def action_name(refresh = false)
- if @action_name.nil? || refresh
- @action_name = (params['action'] || 'index')
- end
-
- @action_name
- end
-
def session_enabled?
request.session_options[:disabled] != false
end
@@ -868,12 +859,11 @@ def reset_session #:doc:
private
def self.view_class
- unless @view_class
+ @view_class ||=
# create a new class based on the default template class and include helper methods
- @view_class = Class.new(ActionView::Base)
- @view_class.send(:include, master_helper_module)
- end
- @view_class
+ returning Class.new(ActionView::Base) do |view_class|
+ view_class.send(:include, master_helper_module)
+ end
end
def self.view_root
@@ -928,6 +918,10 @@ def performed?
@performed_render || @performed_redirect
end
+ def assign_names
+ @action_name = (params['action'] || 'index')
+ end
+
def action_methods
self.class.action_methods
end
@@ -997,9 +991,7 @@ def template_public?(template_name = default_template_name)
end
def template_exempt_from_layout?(template_name = default_template_name)
- template_name.last(3) == "rjs" || @template.pick_template_extension(template_name).to_sym == :rjs
- rescue
- false
+ template_name =~ /\.rjs$/ || (@template.pick_template_extension(template_name) == :rjs rescue false)
end
def assert_existance_of_template_file(template_name)
@@ -1010,20 +1002,22 @@ def assert_existance_of_template_file(template_name)
end
end
- def default_template_name(default_action_name = action_name)
- if default_action_name
- default_action_name = default_action_name.to_s.dup
- strip_out_controller!(default_action_name) if template_path_includes_controller?(default_action_name)
+ def default_template_name(action_name = self.action_name)
+ if action_name
+ action_name = action_name.to_s
+ if action_name.include?('/') && template_path_includes_controller?(action_name)
+ action_name = strip_out_controller(action_name)
+ end
end
- "#{self.class.controller_path}/#{default_action_name}"
+ "#{self.class.controller_path}/#{action_name}"
end
- def strip_out_controller!(path)
- path.replace path.split('/', 2).last
+ def strip_out_controller(path)
+ path.split('/', 2).last
end
def template_path_includes_controller?(path)
- path.to_s['/'] && self.class.controller_path.split('/')[-1] == path.split('/')[0]
+ self.class.controller_path.split('/')[-1] == path.split('/')[0]
end
def process_cleanup
@@ -159,7 +159,6 @@ def stale_session_check!
def session_options_with_string_keys
@session_options_with_string_keys ||= DEFAULT_SESSION_OPTIONS.merge(@session_options).inject({}) { |options, (k,v)| options[k.to_s] = v; options }
- @session_options_with_string_keys
end
end
@@ -44,7 +44,11 @@ def render_component(options)
@controller.send(:render_component_as_string, options)
end
end
-
+
+ # If this controller was instantiated to process a component request,
+ # +parent_controller+ points to the instantiator of this controller.
+ base.send :attr_accessor, :parent_controller
+
base.class_eval do
alias_method :process_cleanup_without_components, :process_cleanup
alias_method :process_cleanup, :process_cleanup_with_components
@@ -54,11 +58,9 @@ def render_component(options)
alias_method :flash_without_components, :flash
alias_method :flash, :flash_with_components
+
+ alias_method :component_request?, :parent_controller
end
-
- # If this controller was instantiated to process a component request,
- # +parent_controller+ points to the instantiator of this controller.
- base.send :attr_accessor, :parent_controller
end
module ClassMethods
@@ -171,10 +173,6 @@ def component_logging(options)
yield
end
end
-
- def component_request?
- !@parent_controller.nil?
- end
def set_session_options_with_components(request)
set_session_options_without_components(request) unless component_request?
@@ -283,22 +283,22 @@ def skip_after_filter(*filters)
# Returns all the before filters for this class and all its ancestors.
def before_filters #:nodoc:
- read_inheritable_attribute("before_filters") || []
+ @before_filters ||= read_inheritable_attribute("before_filters") || []
end
# Returns all the after filters for this class and all its ancestors.
def after_filters #:nodoc:
- read_inheritable_attribute("after_filters") || []
+ @after_filters ||= read_inheritable_attribute("after_filters") || []
end
# Returns a mapping between filters and the actions that may run them.
def included_actions #:nodoc:
- read_inheritable_attribute("included_actions") || {}
+ @included_actions ||= read_inheritable_attribute("included_actions") || {}
end
# Returns a mapping between filters and actions that may not run them.
def excluded_actions #:nodoc:
- read_inheritable_attribute("excluded_actions") || {}
+ @excluded_actions ||= read_inheritable_attribute("excluded_actions") || {}
end
private
@@ -170,7 +170,11 @@ def layout(template_name, conditions = {})
end
def layout_conditions #:nodoc:
- read_inheritable_attribute("layout_conditions")
+ @layout_conditions ||= read_inheritable_attribute("layout_conditions")
+ end
+
+ def default_layout #:nodoc:
+ @default_layout ||= read_inheritable_attribute("layout")
end
private
@@ -205,7 +209,7 @@ def layout_directory_exists_cache
# object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
# weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard.
def active_layout(passed_layout = nil)
- layout = passed_layout || self.class.read_inheritable_attribute("layout")
+ layout = passed_layout || self.class.default_layout
active_layout = case layout
when String then layout
@@ -249,6 +253,7 @@ def render_with_a_layout(options = nil, deprecated_status = nil, deprecated_layo
end
private
+
def apply_layout?(template_with_options, options)
return false if options == :update
template_with_options ? candidate_for_layout?(options) : !template_exempt_from_layout?
@@ -48,30 +48,30 @@ def head?
# For backward compatibility, the post format is extracted from the
# X-Post-Data-Format HTTP header if present.
def content_type
- return @content_type if @content_type
-
- @content_type = @env['CONTENT_TYPE'].to_s.downcase
-
- if @env['HTTP_X_POST_DATA_FORMAT']
- case @env['HTTP_X_POST_DATA_FORMAT'].downcase.to_sym
- when :yaml
- @content_type = 'application/x-yaml'
- when :xml
- @content_type = 'application/xml'
+ @content_type ||=
+ begin
+ content_type = @env['CONTENT_TYPE'].to_s.downcase
+
+ if x_post_format = @env['HTTP_X_POST_DATA_FORMAT']
+ case x_post_format.to_s.downcase
+ when 'yaml'
+ content_type = 'application/x-yaml'
+ when 'xml'
+ content_type = 'application/xml'
+ end
end
- end
-
- @content_type = Mime::Type.lookup(@content_type)
+
+ Mime::Type.lookup(content_type)
+ end
end
def accepts
- return @accepts if @accepts
-
- @accepts = if @env['HTTP_ACCEPT'].to_s.strip.blank?
- [ content_type, Mime::ALL ]
- else
- Mime::Type.parse(@env['HTTP_ACCEPT'])
- end
+ @accepts ||=
+ if @env['HTTP_ACCEPT'].to_s.strip.empty?
+ [ content_type, Mime::ALL ]
+ else
+ Mime::Type.parse(@env['HTTP_ACCEPT'])
+ end
end
# Returns true if the request's "X-Requested-With" header contains
@@ -182,7 +182,11 @@ module CompiledTemplates #:nodoc:
# map method names to the names passed in local assigns so far
@@template_args = {}
# count the number of inline templates
- @@inline_template_count = 0
+ @@inline_template_count = 0
+ # maps template paths without extension to their file extension returned by pick_template_extension.
+ # if for a given path, path.ext1 and path.ext2 exist on the file system, the order of extensions
+ # used by pick_template_extension determines whether ext1 or ext2 will be stored
+ @@cached_template_extension = {}
class ObjectWrapper < Struct.new(:value) #:nodoc:
end
@@ -218,15 +222,15 @@ def initialize(base_path = nil, assigns_for_first_render = {}, controller = nil)
# it's relative to the template_root, otherwise it's absolute. The hash in <tt>local_assigns</tt>
# is made available as local variables.
def render_file(template_path, use_full_path = true, local_assigns = {})
- @first_render = template_path if @first_render.nil?
+ @first_render ||= template_path
if use_full_path
template_path_without_extension, template_extension = path_and_extension(template_path)
if template_extension
template_file_name = full_template_path(template_path_without_extension, template_extension)
else
- template_extension = pick_template_extension(template_path)
+ template_extension = pick_template_extension(template_path).to_s
template_file_name = full_template_path(template_path, template_extension)
end
else
@@ -308,14 +312,15 @@ def compile_and_render_template(extension, template = nil, file_path = nil, loca
end
def pick_template_extension(template_path)#:nodoc:
- if match = delegate_template_exists?(template_path)
- match.first
- elsif erb_template_exists?(template_path): 'rhtml'
- elsif builder_template_exists?(template_path): 'rxml'
- elsif javascript_template_exists?(template_path): 'rjs'
- else
- raise ActionViewError, "No rhtml, rxml, rjs or delegate template found for #{template_path}"
- end
+ @@cached_template_extension[template_path] ||=
+ if match = delegate_template_exists?(template_path)
+ match.first.to_sym
+ elsif erb_template_exists?(template_path): :rhtml
+ elsif builder_template_exists?(template_path): :rxml
+ elsif javascript_template_exists?(template_path): :rjs
+ else
+ raise ActionViewError, "No rhtml, rxml, rjs or delegate template found for #{template_path}"
+ end
end
def delegate_template_exists?(template_path)#:nodoc:
@@ -340,9 +345,10 @@ def file_exists?(template_path)#:nodoc:
if template_file_extension
template_exists?(template_file_name, template_file_extension)
else
- %w(erb builder javascript delegate).any? do |template_type|
- send("#{template_type}_template_exists?", template_path)
- end
+ @@cached_template_extension[template_path] ||
+ %w(erb builder javascript delegate).any? do |template_type|
+ send("#{template_type}_template_exists?", template_path)
+ end
end
end
@@ -21,7 +21,7 @@ def []=(key, value)
end
def update(other_hash)
- other_hash.each_pair {|key, value| regular_writer(convert_key(key), convert_value(value))}
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
self
end
alias_method :merge!, :update

0 comments on commit d19e8f4

Please sign in to comment.