From d0301e13f4d6e2ddf956ecf80e85384c1ea5346c Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Sat, 8 Aug 2009 12:26:58 -0300 Subject: First pass at making partial rendering an Object. More cleanup to come. --- actionpack/lib/abstract_controller/layouts.rb | 18 +-- .../metal/rendering_controller.rb | 3 - actionpack/lib/action_view/render/partials.rb | 142 ++++++++++++--------- actionpack/lib/action_view/render/rendering.rb | 3 +- 4 files changed, 93 insertions(+), 73 deletions(-) (limited to 'actionpack') diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index c1fb80415b..0063d54149 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -89,16 +89,18 @@ module AbstractController end def render_to_body(options = {}) + # In the case of a partial with a layout, handle the layout + # here, and make sure the view does not try to handle it + layout = options.delete(:layout) if options.key?(:partial) + response = super - if options.key?(:partial) - # This is a little bit messy. We need to explicitly handle partial - # layouts here since the core lookup logic is in the view, but - # we need to determine the layout based on the controller - if options.key?(:layout) - layout = _layout_for_option(options[:layout], options[:_template].details) - response = layout.render(view_context, options[:locals]) { response } - end + # This is a little bit messy. We need to explicitly handle partial + # layouts here since the core lookup logic is in the view, but + # we need to determine the layout based on the controller + if layout + layout = _layout_for_option(layout, options[:_template].details) + response = layout.render(view_context, options[:locals] || {}) { response } end response diff --git a/actionpack/lib/action_controller/metal/rendering_controller.rb b/actionpack/lib/action_controller/metal/rendering_controller.rb index c8922290f3..5b1be763ad 100644 --- a/actionpack/lib/action_controller/metal/rendering_controller.rb +++ b/actionpack/lib/action_controller/metal/rendering_controller.rb @@ -53,9 +53,6 @@ module ActionController super end - def _render_partial(partial, options) - end - def _process_options(options) status, content_type, location = options.values_at(:status, :content_type, :location) self.status = status if status diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index c559a572b0..986d3af454 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -170,95 +170,117 @@ module ActionView # <%- end -%> # <% end %> module Partials - extend ActiveSupport::Memoizable extend ActiveSupport::Concern - included do - attr_accessor :_partial - end - - module ClassMethods - def _partial_names - @_partial_names ||= ActiveSupport::ConcurrentHash.new + class PartialRenderer + def self.partial_names + @partial_names ||= Hash.new {|h,k| h[k] = ActiveSupport::ConcurrentHash.new } end - end - def render_partial(options) - @assigns_added = false - # TODO: Handle other details here. - self.formats = options[:_details][:formats] - _render_partial(options) - end + def initialize(view_context, options, formats) + object = options[:partial] - def _render_partial(options, &block) #:nodoc: - options[:locals] ||= {} + @view, @formats = view_context, formats + @options = options || {} - path = partial = options[:partial] + if object.is_a?(String) + @path = object + elsif + @object = object + @path = partial_path unless collection + end - if partial.respond_to?(:to_ary) - return _render_partial_collection(partial, options, &block) - elsif !partial.is_a?(String) - options[:object] = object = partial - path = _partial_path(object) + @locals = options[:locals] || {} + @object ||= @options[:object] || @locals[:object] + @layout = options[:layout] end - _render_partial_object(_pick_partial_template(path), options, &block) - end + def render(&block) + template = find if @path - private - def _partial_path(object) - self.class._partial_names[[controller.class, object.class]] ||= begin - name = object.class.model_name - if controller_path && controller_path.include?("/") - File.join(File.dirname(controller_path), name.partial_path) - else - name.partial_path - end + if collection + render_collection(template, &block) + else + render_object(template, &block) end end - def _render_partial_template(template, locals, object, options = {}, &block) - options[:_template] = template - locals[:object] = locals[template.variable_name] = object - locals[options[:as]] = object if options[:as] + def render_template(template, &block) + @options[:_template] = template + @locals[:object] = @locals[template.variable_name] = @object + @locals[@options[:as]] = @object if @options[:as] - _render_single_template(template, locals, &block) + content = @view._render_single_template(template, @locals, &block) + return content if block_given? || !@layout + find(@layout).render(@view, @locals) { content } end - def _render_partial_object(template, options, &block) - if options.key?(:collection) - _render_partial_collection(options.delete(:collection), options, template, &block) - else - locals = (options[:locals] ||= {}) - object = options[:object] || locals[:object] || locals[template.variable_name] - - _render_partial_template(template, locals, object, options, &block) - end + def render_object(template, &block) + @object ||= @locals[template.variable_name] + render_template(template, &block) end - def _render_partial_collection(collection, options = {}, template = nil, &block) #:nodoc: - options[:_template] ||= template + def render_collection(passed_template = nil, &block) + @options[:_template] = passed_template return nil if collection.blank? - if options.key?(:spacer_template) - spacer = _render_partial(:partial => options[:spacer_template]) + if @options.key?(:spacer_template) + spacer = @view.render_partial( + :partial => @options[:spacer_template], :_details => @options[:_details]) end - locals, index = options[:locals] || {}, 0 + index = 0 - collection.map do |object| - tmp = template || _pick_partial_template(_partial_path(object)) - locals[tmp.counter_name] = index + collection.map do |@object| + @path = partial_path + template = passed_template || find + @locals[template.counter_name] = index index += 1 - _render_partial_template(tmp, locals, object, options, &block) + render_template(template, &block) end.join(spacer) end - def _pick_partial_template(partial_path) #:nodoc: - prefix = controller_path unless partial_path.include?(?/) - find(partial_path, {:formats => formats}, prefix, true) + private + def collection + @collection ||= if @object.respond_to?(:to_ary) + @object + elsif @options.key?(:collection) + @options[:collection] || [] + end end + + def find(path = @path) + prefix = @view.controller.controller_path unless path.include?(?/) + @view.find(path, {:formats => @view.formats}, prefix, true) + end + + def partial_path(object = @object) + self.class.partial_names[@view.controller.class][object.class] ||= begin + return nil unless object.class.respond_to?(:model_name) + + name = object.class.model_name + path = @view.controller_path + if path && path.include?(?/) + File.join(File.dirname(path), name.partial_path) + else + name.partial_path + end + end + end + end + + def render_partial(options) + @assigns_added = false + # TODO: Handle other details here. + self.formats = options[:_details][:formats] if options[:_details] + _render_partial(options) + end + + def _render_partial(options, &block) #:nodoc: + PartialRenderer.new(self, options, formats).render(&block) + end + end end diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 742b965556..c7afc56e3b 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -20,8 +20,7 @@ module ActionView if block_given? return concat(_render_partial(options.merge(:partial => layout), &block)) elsif options.key?(:partial) - layout = _pick_partial_template(layout) if layout - return _render_content(_render_partial(options), layout, options[:locals]) + return _render_partial(options) end layout = find(layout, {:formats => formats}) if layout -- cgit v1.2.3