aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_view/render
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_view/render')
-rw-r--r--actionpack/lib/action_view/render/partials.rb133
-rw-r--r--actionpack/lib/action_view/render/rendering.rb79
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