diff options
Diffstat (limited to 'actionpack/lib/action_view/render')
-rw-r--r-- | actionpack/lib/action_view/render/partials.rb | 133 | ||||
-rw-r--r-- | actionpack/lib/action_view/render/rendering.rb | 79 |
2 files changed, 100 insertions, 112 deletions
diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 83175ab4cf..7f10f54d2e 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -173,44 +173,50 @@ module ActionView extend ActiveSupport::Concern class PartialRenderer - def self.partial_names - @partial_names ||= Hash.new {|h,k| h[k] = ActiveSupport::ConcurrentHash.new } - end + PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} } + TEMPLATES = Hash.new {|h,k| h[k] = {} } - def self.formats - @formats ||= Hash.new {|h,k| h[k] = Hash.new{|h,k| h[k] = Hash.new {|h,k| h[k] = {}}}} - end + attr_reader :template def initialize(view_context, options, block) - partial = options[:partial] - - @memo = {} @view = view_context - @options = options - @locals = options[:locals] || {} - @block = block - - # Set up some instance variables to speed up memoizing - @partial_names = self.class.partial_names[@view.controller.class] - @templates = self.class.formats - @format = view_context.formats - - # Set up the object and path - @object = partial.is_a?(String) ? options[:object] : partial - @path = partial_path(partial) + @partial_names = PARTIAL_NAMES[@view.controller.class] + + key = Thread.current[:format_locale_key] + @templates = TEMPLATES[key] if key + + setup(options, block) + end + + def setup(options, block) + partial = options[:partial] + + @options = options + @locals = options[:locals] || {} + @block = block + + if String === partial + @object = options[:object] + @path = partial + else + @object = partial + @path = partial_path(partial) + end end def render - return render_collection if collection - - template = find_template - render_template(template, @object || @locals[template.variable_name]) + if @collection = collection + render_collection + else + @template = template = find_template + render_template(template, @object || @locals[template.variable_name]) + end end def render_collection - @options[:_template] = template = find_template + @template = template = find_template - return nil if collection.blank? + return nil if @collection.blank? if @options.key?(:spacer_template) spacer = find_template(@options[:spacer_template]).render(@view, @locals) @@ -223,57 +229,58 @@ module ActionView def collection_with_template(template) options = @options - segments, locals, as = [], @locals, options[:as] || :object + segments, locals, as = [], @locals, options[:as] || template.variable_name - variable_name = template.variable_name counter_name = template.counter_name locals[counter_name] = -1 - collection.each do |object| + @collection.each do |object| locals[counter_name] += 1 - locals[variable_name] = object - locals[as] = object if as + locals[as] = object segments << template.render(@view, locals) end + + @template = template segments end def collection_without_template options = @options - segments, locals, as = [], @locals, options[:as] || :object + segments, locals, as = [], @locals, options[:as] index, template = -1, nil - collection.each do |object| + @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 + @template = template segments end def render_template(template, object = @object) - @options[:_template] ||= template + options, locals, view = @options, @locals, @view + locals[options[:as] || template.variable_name] = object - # TODO: is locals[:object] really necessary? - @locals[:object] = @locals[template.variable_name] = object - @locals[@options[:as]] = object if @options[:as] + content = template.render(view, locals) do |*name| + @view._layout_for(*name, &@block) + end - content = @view._render_single_template(template, @locals, &@block) - return content if @block || !@options[:layout] - find_template(@options[:layout]).render(@view, @locals) { content } + if @block || !options[:layout] + content + else + find_template(options[:layout]).render(@view, @locals) { content } + end end - private def collection - @collection ||= if @object.respond_to?(:to_ary) + if @object.respond_to?(:to_ary) @object elsif @options.key?(:collection) @options[:collection] || [] @@ -281,15 +288,19 @@ module ActionView end def find_template(path = @path) - return if !path - @templates[path][@view.controller_path][@format][I18n.locale] ||= begin - prefix = @view.controller.controller_path unless path.include?(?/) - @view.find(path, {:formats => @view.formats}, prefix, true) + unless @templates + path && _find_template(path) + else + path && @templates[path] ||= _find_template(path) end end + + def _find_template(path) + prefix = @view.controller.controller_path unless path.include?(?/) + @view.find(path, {:formats => @view.formats}, prefix, true) + end def partial_path(object = @object) - return object if object.is_a?(String) @partial_names[object.class] ||= begin return nil unless object.respond_to?(:to_model) @@ -302,14 +313,26 @@ module ActionView end def render_partial(options) - @assigns_added = false - # TODO: Handle other details here. - self.formats = options[:_details][:formats] if options[:_details] - _render_partial(options) + _evaluate_assigns_and_ivars + + details = options[:_details] + + # Is this needed + self.formats = details[:formats] if details + renderer = PartialRenderer.new(self, options, nil) + text = renderer.render + options[:_template] = renderer.template + text end def _render_partial(options, &block) #:nodoc: - PartialRenderer.new(self, options, block).render + if @renderer + @renderer.setup(options, block) + else + @renderer = PartialRenderer.new(self, options, block) + end + + @renderer.render end end diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index c7afc56e3b..b0b75918b7 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -12,8 +12,6 @@ module ActionView # as the locals hash. def render(options = {}, locals = {}, &block) #:nodoc: case options - when String, NilClass - _render_partial(:partial => options, :locals => locals || {}) when Hash layout = options[:layout] @@ -35,26 +33,8 @@ module ActionView end when :update update_page(&block) - end - end - - def _render_content(content, layout, locals) - return content unless layout - - locals ||= {} - - if controller && layout - @_layout = layout.identifier - logger.info("Rendering template within #{layout.identifier}") if logger - end - - begin - old_content, @_content_for[:layout] = @_content_for[:layout], content - - @cached_content_for_layout = @_content_for[:layout] - _render_single_template(layout, locals) - ensure - @_content_for[:layout] = old_content + else + _render_partial(:partial => options, :locals => locals) end end @@ -90,48 +70,25 @@ module ActionView # In this case, the layout would receive the block passed into <tt>render :layout</tt>, # and the Struct specified in the layout would be passed into the block. The result # would be <html>Hello David</html>. - def _layout_for(names, &block) - with_output_buffer do - # This is due to the potentially ambiguous use of yield when - # a block is passed in to a template *and* there is a content_for() - # of the same name. Suggested solution: require explicit use of content_for - # in these ambiguous cases. - # - # We would be able to continue supporting yield in all non-ambiguous - # cases. Question: should we deprecate yield in favor of content_for - # and reserve yield for cases where there is a yield into a real block? - if @_content_for.key?(names.first) || !block_given? - return @_content_for[names.first || :layout] - else - return yield(names) - end - end - end + def _layout_for(name = nil) + return @_content_for[name || :layout] if !block_given? || name - def _render_single_template(template, locals = {}, &block) - with_template(template) do - template.render(self, locals) do |*names| - _layout_for(names, &block) - end - end - rescue Exception => e - if e.is_a?(TemplateError) - e.sub_template_of(template) - raise e - else - raise TemplateError.new(template, assigns, e) + with_output_buffer do + return yield end end def _render_inline(inline, layout, options) handler = Template.handler_class_for_extension(options[:type] || "erb") template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) - content = _render_single_template(template, options[:locals] || {}) - layout ? _render_content(content, layout, options[:locals]) : content + locals = options[:locals] || {} + content = template.render(self, locals) + content = layout.render(self, locals) {|*name| _layout_for(*name) { content } } if layout + content end def _render_text(text, layout, options) - layout ? _render_content(text, layout, options[:locals]) : text + text = layout.render(self, options[:locals]) { text } if layout end # This is the API to render a ViewContext's template from a controller. @@ -141,7 +98,7 @@ module ActionView # _layout:: The layout, if any, to wrap the Template in # _partial:: true if the template is a partial def render_template(options) - @assigns_added = nil + _evaluate_assigns_and_ivars template, layout, partial = options.values_at(:_template, :_layout, :_partial) _render_template(template, layout, options, partial) end @@ -158,10 +115,18 @@ module ActionView content = if partial _render_partial_object(template, options) else - _render_single_template(template, locals) + template.render(self, locals) end - _render_content(content, layout, locals) + @cached_content_for_layout = content + @_content_for[:layout] = content + + if layout + @_layout = layout.identifier + logger.info("Rendering template within #{layout.identifier}") if logger + content = layout.render(self, locals) {|*name| _layout_for(*name) } + end + content end end end
\ No newline at end of file |