Memoize ActionView::Base pick_template and find_partial_path for rendering duration

This commit is contained in:
Joshua Peek 2008-07-22 10:27:32 -05:00
parent 8a87d8a6c2
commit bc5896e708
5 changed files with 26 additions and 17 deletions

View File

@ -1261,6 +1261,8 @@ module ActionController #:nodoc:
def template_exempt_from_layout?(template_name = default_template_name)
template_name = @template.pick_template(template_name).to_s if @template
@@exempt_from_layout.any? { |ext| template_name =~ ext }
rescue ActionView::MissingTemplate
false
end
def default_template_name(action_name = self.action_name)

View File

@ -323,8 +323,8 @@ module ActionView #:nodoc:
if self.class.warn_cache_misses && logger = ActionController::Base.logger
logger.debug "[PERFORMANCE] Rendering a template that was " +
"not found in view path. Templates outside the view path are " +
"not cached and result in expensive disk operations. Move this " +
"file into #{view_paths.join(':')} or add the folder to your " +
"not cached and result in expensive disk operations. Move this " +
"file into #{view_paths.join(':')} or add the folder to your " +
"view path list"
end
@ -332,6 +332,9 @@ module ActionView #:nodoc:
end
end
extend ActiveSupport::Memoizable
memoize :pick_template
private
# Renders the template present at <tt>template_path</tt>. The hash in <tt>local_assigns</tt>
# is made available as local variables.

View File

@ -102,6 +102,8 @@ module ActionView
#
# As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
module Partials
extend ActiveSupport::Memoizable
private
def render_partial(partial_path, object_assigns = nil, local_assigns = {}) #:nodoc:
local_assigns ||= {}
@ -129,14 +131,12 @@ module ActionView
local_assigns = local_assigns ? local_assigns.clone : {}
spacer = partial_spacer_template ? render(:partial => partial_spacer_template) : ''
_paths = {}
_templates = {}
index = 0
collection.map do |object|
_partial_path ||= partial_path || ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path)
path = _paths[_partial_path] ||= find_partial_path(_partial_path)
template = _templates[path] ||= pick_template(path)
path = find_partial_path(_partial_path)
template = pick_template(path)
local_assigns[template.counter_name] = index
result = template.render_partial(self, object, local_assigns, as)
index += 1
@ -153,5 +153,6 @@ module ActionView
"_#{partial_path}"
end
end
memoize :find_partial_path
end
end

View File

@ -75,7 +75,7 @@ module ActionView #:nodoc:
load_paths = Array(load_paths) + [nil]
load_paths.each do |load_path|
file = [load_path, path].compact.join('/')
return load_path, file if File.exist?(file)
return load_path, file if File.exist?(file) && File.file?(file)
end
raise MissingTemplate.new(load_paths, path)
end

View File

@ -4,7 +4,6 @@ require 'controller/fake_models'
uses_mocha 'TestTemplateRecompilation' do
class CompiledTemplatesTest < Test::Unit::TestCase
def setup
@view = ActionView::Base.new(ActionController::Base.view_paths, {})
@compiled_templates = ActionView::Base::CompiledTemplates
@compiled_templates.instance_methods.each do |m|
@compiled_templates.send(:remove_method, m) if m =~ /^_run_/
@ -13,29 +12,33 @@ uses_mocha 'TestTemplateRecompilation' do
def test_template_gets_compiled
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", @view.render("test/hello_world.erb")
assert_equal "Hello world!", render("test/hello_world.erb")
assert_equal 1, @compiled_templates.instance_methods.size
end
def test_template_gets_recompiled_when_using_different_keys_in_local_assigns
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", @view.render("test/hello_world.erb")
assert_equal "Hello world!", @view.render("test/hello_world.erb", {:foo => "bar"})
assert_equal "Hello world!", render("test/hello_world.erb")
assert_equal "Hello world!", render("test/hello_world.erb", {:foo => "bar"})
assert_equal 2, @compiled_templates.instance_methods.size
end
def test_compiled_template_will_not_be_recompiled_when_rendered_with_identical_local_assigns
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", @view.render("test/hello_world.erb")
assert_equal "Hello world!", render("test/hello_world.erb")
ActionView::Template.any_instance.expects(:compile!).never
assert_equal "Hello world!", @view.render("test/hello_world.erb")
assert_equal "Hello world!", render("test/hello_world.erb")
end
def test_compiled_template_will_always_be_recompiled_when_rendered_if_template_is_outside_cache
def test_compiled_template_will_be_recompiled_when_rendered_if_template_is_outside_cache
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", @view.render("#{FIXTURE_LOAD_PATH}/test/hello_world.erb")
ActionView::Template.any_instance.expects(:compile!).times(3)
3.times { assert_equal "Hello world!", @view.render("#{FIXTURE_LOAD_PATH}/test/hello_world.erb") }
assert_equal "Hello world!", render("#{FIXTURE_LOAD_PATH}/test/hello_world.erb")
assert_equal 1, @compiled_templates.instance_methods.size
end
private
def render(*args)
ActionView::Base.new(ActionController::Base.view_paths, {}).render(*args)
end
end
end