aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael Mendonça França <rafaelmfranca@gmail.com>2013-07-07 13:44:16 -0300
committerRafael Mendonça França <rafaelmfranca@gmail.com>2013-07-07 13:44:16 -0300
commit09f6fe1cd4099837c5801fe654804ae058c211b4 (patch)
treeda14b61b5048406d6dd83ed5b23d7ff539fbec3c
parenta67cc28311b0ecb4282ca7d80b5ece959d22628f (diff)
downloadrails-09f6fe1cd4099837c5801fe654804ae058c211b4.tar.gz
rails-09f6fe1cd4099837c5801fe654804ae058c211b4.tar.bz2
rails-09f6fe1cd4099837c5801fe654804ae058c211b4.zip
Fix "Stack Level Too Deep" error when rendering recursive partials
When rendering recursive partial Action View is trying to generate the view digest infinitly causing a stack level error. Fixes #11340
-rw-r--r--actionview/CHANGELOG.md6
-rw-r--r--actionview/lib/action_view/digestor.rb10
-rw-r--r--actionview/test/fixtures/digestor/level/_recursion.html.erb1
-rw-r--r--actionview/test/fixtures/digestor/level/recursion.html.erb1
-rw-r--r--actionview/test/template/digestor_test.rb25
5 files changed, 40 insertions, 3 deletions
diff --git a/actionview/CHANGELOG.md b/actionview/CHANGELOG.md
index 64393b4089..ba1c7936b3 100644
--- a/actionview/CHANGELOG.md
+++ b/actionview/CHANGELOG.md
@@ -1,3 +1,9 @@
+* Fix "Stack Level Too Deep" error when redering recursive partials.
+
+ Fixes #11340.
+
+ *Rafael Mendonça França*
+
* Added an `enforce_utf8` hash option for `form_tag` method.
Control to output a hidden input tag with name `utf8` without monkey
diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb
index 9324a1ac50..a674e4d7ea 100644
--- a/actionview/lib/action_view/digestor.rb
+++ b/actionview/lib/action_view/digestor.rb
@@ -7,10 +7,14 @@ module ActionView
@@cache = ThreadSafe::Cache.new
def self.digest(name, format, finder, options = {})
- cache_key = [name, format] + Array.wrap(options[:dependencies])
- @@cache[cache_key.join('.')] ||= begin
+ cache_key = ([name, format] + Array.wrap(options[:dependencies])).join('.')
+ @@cache.fetch(cache_key) do
+ @@cache[cache_key] ||= nil if options[:partial] # Prevent re-entry
+
klass = options[:partial] || name.include?("/_") ? PartialDigestor : Digestor
- klass.new(name, format, finder, options).digest
+ digest = klass.new(name, format, finder, options).digest
+
+ @@cache[cache_key] = digest # Store the value
end
end
diff --git a/actionview/test/fixtures/digestor/level/_recursion.html.erb b/actionview/test/fixtures/digestor/level/_recursion.html.erb
new file mode 100644
index 0000000000..ee5aaf09c3
--- /dev/null
+++ b/actionview/test/fixtures/digestor/level/_recursion.html.erb
@@ -0,0 +1 @@
+<%= render 'recursion' %>
diff --git a/actionview/test/fixtures/digestor/level/recursion.html.erb b/actionview/test/fixtures/digestor/level/recursion.html.erb
new file mode 100644
index 0000000000..ee5aaf09c3
--- /dev/null
+++ b/actionview/test/fixtures/digestor/level/recursion.html.erb
@@ -0,0 +1 @@
+<%= render 'recursion' %>
diff --git a/actionview/test/template/digestor_test.rb b/actionview/test/template/digestor_test.rb
index 06735c30d3..07f8d36d93 100644
--- a/actionview/test/template/digestor_test.rb
+++ b/actionview/test/template/digestor_test.rb
@@ -95,6 +95,31 @@ class TemplateDigestorTest < ActionView::TestCase
end
end
+ def test_recursion_in_renders
+ assert digest("level/recursion") # assert recursion is possible
+ assert_not_nil digest("level/recursion") # assert digest is stored
+ end
+
+ def test_chaning_the_top_templete_on_recursion
+ assert digest("level/recursion") # assert recursion is possible
+
+ assert_digest_difference("level/recursion") do
+ change_template("level/recursion")
+ end
+
+ assert_not_nil digest("level/recursion") # assert digest is stored
+ end
+
+ def test_chaning_the_partial_templete_on_recursion
+ assert digest("level/recursion") # assert recursion is possible
+
+ assert_digest_difference("level/recursion") do
+ change_template("level/_recursion")
+ end
+
+ assert_not_nil digest("level/recursion") # assert digest is stored
+ end
+
def test_dont_generate_a_digest_for_missing_templates
assert_equal '', digest("nothing/there")
end