aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/lib/action_view/template.rb95
-rw-r--r--actionpack/test/template/template_test.rb12
2 files changed, 66 insertions, 41 deletions
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 1268b2f426..04ff752e64 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -125,34 +125,41 @@ module ActionView
@compiled = false
end
+ # Render a template. If the template was not compiled yet, it is done
+ # exactly before rendering.
+ #
+ # This method is instrumented as "!render_template.action_view". Notice that
+ # we use a bang in this instrumentation because you don't want to
+ # consume this in production. This is only slow if it's being listened to.
def render(view, locals, &block)
- # Notice that we use a bang in this instrumentation because you don't want to
- # consume this in production. This is only slow if it's being listened to.
ActiveSupport::Notifications.instrument("!render_template.action_view", :virtual_path => @virtual_path) do
compile!(view)
view.send(method_name, locals, &block)
end
rescue Exception => e
- if e.is_a?(Template::Error)
- e.sub_template_of(self)
- raise e
- else
- raise Template::Error.new(refresh(view) || self, view.respond_to?(:assigns) ? view.assigns : {}, e)
- end
+ handle_render_error(view, e)
end
def mime_type
@mime_type ||= Mime::Type.lookup_by_extension(@formats.first.to_s) if @formats.first
end
- # TODO Remove me
- def variable_name
- @variable_name ||= @virtual_path[%r'_?(\w+)(\.\w+)*$', 1].to_sym
- end
-
- # TODO Remove me
- def counter_name
- @counter_name ||= "#{variable_name}_counter".to_sym
+ # Receives a view object and return a template similar to self by using @virtual_path.
+ #
+ # This method is useful if you have a template object but it does not contain its source
+ # anymore since it was already compiled. In such cases, all you need to do is to call
+ # refresh passing in the view object.
+ #
+ # Notice this method raises an error if the template to be refreshed does not have a
+ # virtual path set (true just for inline templates).
+ def refresh(view)
+ raise "A template need to have a virtual path in order to be refreshed" unless @virtual_path
+ pieces = @virtual_path.split("/")
+ name = pieces.pop
+ partial = name.sub!(/^_/, "")
+ view.lookup_context.disable_cache do
+ view.find_template(name, pieces.join, partial || false, @locals)
+ end
end
def inspect
@@ -164,24 +171,26 @@ module ActionView
end
end
- def compile!(view)
- return if @compiled
+ protected
- if view.is_a?(ActionView::CompiledTemplates)
- mod = ActionView::CompiledTemplates
- else
- mod = view.singleton_class
- end
+ # Compile a template. This method ensures a template is compiled
+ # just once and removes the source after it is compiled.
+ def compile!(view) #:nodoc:
+ return if @compiled
- compile(view, mod)
+ if view.is_a?(ActionView::CompiledTemplates)
+ mod = ActionView::CompiledTemplates
+ else
+ mod = view.singleton_class
+ end
- # Just discard the source if we have a virtual path. This
- # means we can get the template back.
- @source = nil if @virtual_path
- @compiled = true
- end
+ compile(view, mod)
- protected
+ # Just discard the source if we have a virtual path. This
+ # means we can get the template back.
+ @source = nil if @virtual_path
+ @compiled = true
+ end
# Among other things, this method is responsible for properly setting
# the encoding of the source. Until this point, we assume that the
@@ -203,9 +212,8 @@ module ActionView
# encode the source into Encoding.default_internal. In general,
# this means that templates will be UTF-8 inside of Rails,
# regardless of the original source encoding.
- def compile(view, mod)
+ def compile(view, mod) #:nodoc:
method_name = self.method_name
- locals_code = @locals.map { |key| "#{key} = local_assigns[:#{key}];" }.join
if source.encoding_aware?
# Look for # encoding: *. If we find one, we'll encode the
@@ -281,21 +289,26 @@ module ActionView
end
end
- def refresh(view)
- return unless @virtual_path
- pieces = @virtual_path.split("/")
- name = pieces.pop
- partial = name.sub!(/^_/, "")
- view.lookup_context.disable_cache do
- view.find_template(name, pieces.join, partial || false, @locals)
+ def handle_render_error(view, e) #:nodoc:
+ if e.is_a?(Template::Error)
+ e.sub_template_of(self)
+ raise e
+ else
+ assigns = view.respond_to?(:assigns) ? view.assigns : {}
+ template = @virtual_path ? refresh(view) : self
+ raise Template::Error.new(template, assigns, e)
end
end
- def method_name
+ def locals_code #:nodoc:
+ @locals.map { |key| "#{key} = local_assigns[:#{key}];" }.join
+ end
+
+ def method_name #:nodoc:
@method_name ||= "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}".gsub('-', "_")
end
- def identifier_method_name
+ def identifier_method_name #:nodoc:
inspect.gsub(/[^a-z_]/, '_')
end
end
diff --git a/actionpack/test/template/template_test.rb b/actionpack/test/template/template_test.rb
index 27b42006e3..00bfbbccd6 100644
--- a/actionpack/test/template/template_test.rb
+++ b/actionpack/test/template/template_test.rb
@@ -49,6 +49,18 @@ class TestERBTemplate < ActiveSupport::TestCase
assert_equal "Hello", render
end
+ def test_template_loses_its_source_after_rendering
+ @template = new_template
+ render
+ assert_nil @template.source
+ end
+
+ def test_template_does_not_lose_its_source_after_rendering_if_it_does_not_have_a_virtual_path
+ @template = new_template("Hello", :virtual_path => nil)
+ render
+ assert_equal "Hello", @template.source
+ end
+
def test_locals
@template = new_template("<%= my_local %>")
@template.locals = [:my_local]