Permalink
Browse files

Further experimentation. Was able to cut the cost of rendering 100 pa…

…rtials in a collection in half.

  To discuss: What are the desired semantics (if any) for layouts in a collection. There are no
  tests for it at present, and I'm not sure if it's needed at all.

  Deprecated on this branch: `object` pointing at the current object in partials. You can still
  use the partial name, or use :as to achieve the same thing. This is obviously up for discussion.
  • Loading branch information...
1 parent bef7576 commit 4945d8223964d4ccb3c0a0f4107f15ae1c6c4a09 @wycats wycats committed Aug 10, 2009
View
4 actionpack/examples/minimal.rb
@@ -104,22 +104,22 @@ def index
unless ENV["PROFILE"]
Runner.run(BasePostController.action(:overhead), N, 'overhead', false)
Runner.run(BasePostController.action(:index), N, 'index', false)
+ Runner.run(BasePostController.action(:show_template), N, 'template', false)
Runner.run(BasePostController.action(:partial), N, 'partial', false)
Runner.run(BasePostController.action(:many_partials), N, 'many_partials', false)
Runner.run(BasePostController.action(:partial_collection), N, 'collection', false)
Runner.run(BasePostController.action(:hundred_partials), N, 'hundred_partials', false)
Runner.run(BasePostController.action(:large_collection), N, 'large_collection', false)
- Runner.run(BasePostController.action(:show_template), N, 'template', false)
(ENV["M"] || 1).to_i.times do
Runner.run(BasePostController.action(:overhead), N, 'overhead')
Runner.run(BasePostController.action(:index), N, 'index')
+ Runner.run(BasePostController.action(:show_template), N, 'template')
Runner.run(BasePostController.action(:partial), N, 'partial')
Runner.run(BasePostController.action(:many_partials), N, 'many_partials')
Runner.run(BasePostController.action(:partial_collection), N, 'collection')
Runner.run(BasePostController.action(:hundred_partials), N, 'hundred_partials')
Runner.run(BasePostController.action(:large_collection), N, 'large_collection')
- Runner.run(BasePostController.action(:show_template), N, 'template')
end
else
Runner.run(BasePostController.action(ENV["PROFILE"].to_sym), N, ENV["PROFILE"])
View
12 actionpack/examples/views/_hundred_partials.erb
@@ -0,0 +1,12 @@
+<% 10.times do %>
+ <%= render :partial => '/hello' %>
+ <%= render :partial => '/hello' %>
+ <%= render :partial => '/hello' %>
+ <%= render :partial => '/hello' %>
+ <%= render :partial => '/hello' %>
+ <%= render :partial => '/hello' %>
+ <%= render :partial => '/hello' %>
+ <%= render :partial => '/hello' %>
+ <%= render :partial => '/hello' %>
+ <%= render :partial => '/hello' %>
+<% end %>
View
49 actionpack/lib/action_view/render/partials.rb
@@ -207,25 +207,56 @@ def render
end
def render_collection
- # Even if no template is rendered, this will ensure that the MIME type
- # for the empty response is the same as the provided template
- @options[:_template] = default_template = find_template
+ @options[:_template] = template = find_template
return nil if collection.blank?
if @options.key?(:spacer_template)
spacer = find_template(@options[:spacer_template]).render(@view, @locals)
end
- segments = []
+ result = template ? collection_with_template(template) : collection_without_template
+ result.join(spacer)
+ end
+
+ def collection_with_template(template)
+ options = @options
+
+ segments, locals, as = [], @locals, options[:as]
+
+ [].tap do |segments|
+ variable_name = template.variable_name
+ counter_name = template.counter_name
+ locals[counter_name] = -1
- collection.each_with_index do |object, index|
- template = default_template || find_template(partial_path(object))
- @locals[template.counter_name] = index
- segments << render_template(template, object)
+ collection.each do |object|
+ locals[counter_name] += 1
+ locals[variable_name] = object
+ locals[as] = object if as
+
+ segments << template.render(@view, locals)
+ end
end
+ end
- segments.join(spacer)
+ def collection_without_template
+ options = @options
+
+ segments, locals, as = [], @locals, options[:as]
+ index, template = -1, nil
+
+ [].tap do |segments|
+ collection.each do |object|
+ template = find_template(partial_path(object))
+ locals[template.counter_name] = (index += 1)
+ locals[template.variable_name] = object
+ locals[as] = object if as
+
+ segments << template.render(@view, locals)
+ end
+
+ @options[:_template] = template
+ end
end
def render_template(template, object = @object)
View
20 actionpack/lib/action_view/test_case.rb
@@ -9,14 +9,16 @@ def initialize(*args)
end
attr_internal :rendered
- alias_method :_render_template_without_template_tracking, :_render_single_template
- def _render_single_template(template, local_assigns, &block)
- if template.respond_to?(:identifier) && template.present?
- @_rendered[:partials][template] += 1 if template.partial?
- @_rendered[:template] ||= []
- @_rendered[:template] << template
- end
- _render_template_without_template_tracking(template, local_assigns, &block)
+ end
+
+ class Template
+ alias_method :render_without_tracking, :render
+ def render(view, locals, &blk)
+ rendered = view.rendered
+ rendered[:partials][self] += 1 if partial?
+ rendered[:template] ||= []
+ rendered[:template] << self
+ render_without_tracking(view, locals, &blk)
end
end
@@ -68,7 +70,7 @@ class TestController < ActionController::Base
def initialize
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
-
+
@params = {}
send(:initialize_current_url)
end

0 comments on commit 4945d82

Please sign in to comment.