ccocchi / rabl-rails

Rails 4.2+ templating system with JSON, XML and Plist support.
MIT License
209 stars 51 forks source link

ActionView::Template::Error: stack level too deep #33

Closed abrisse closed 11 years ago

abrisse commented 11 years ago

When migrating from rabl to rabl-rails I encounter a problem. Let's say you have 2 views in which you can extends each other under 2 different conditions that cannot be true at the same time.

Postulate : condition_A = !condition_B

# x/show.rabl
object :@x
attributes :id

condition(->(_) { condition_A } do
  extends 'y/show'
end
# y/show.rabl
object :@y
attributes :id

condition(->(_) { condition_B } do
  extends 'x/show'
end

That case triggers a ActionView::Template::Error: stack level too deep error when rendered. I guess that because the views are compiled contrary to the rabl gems.

ccocchi commented 11 years ago

Hmm no, this should word because extends will only be called if the condition is true. I think the problem is that both your condition are true in your case.

abrisse commented 11 years ago

@ccocchi : this is definitely a bug. Try to define in a rabl template 'items/show.rabl' :

object @resource

condition(->(item) { false }) do
  extends 'items/show'
end

It will raise :

ActionView::Template::Error (stack level too deep):
  rabl-rails (0.3.1) lib/rabl-rails/compiler.rb:17

Looks like the block is executed even if the condition is false. In fact the block won't be displayed if the condition is false but will nevertheless be executed.

ccocchi commented 11 years ago

You're right, condition body are evaluated at compilation time so it will raise, but it is not a bug. You're trying to introduce a circular reference which is never a good idea, and is often due to a bad design so it won't be added to rabl-rails.

You can resolve your issue by extracting into a partial everything you will need in your x template from y template, and include it once in your y template and once in your x template inside your condition body. This way you will never a case of circular reference, which is a lot safer in my opinion.

brunoald commented 9 years ago

I can't see a problem on using circular references when you have a clear "breakpoint". As far as I know, most recursive algorithms work based on this premise. You should only be careful ensuring there's always a "breakpoint". In my opinion, recursive structures are not necessarily bad design. It might be the case that they're a requirement. I'm trying to create a recursive JSON structure of comments within comments, but I'm getting the same problem that abrisse got.

ccocchi commented 9 years ago

You're right, it makes sense when you're doing recursive templates, but that's different from what @abrisse was trying to achieve.

At the moment you won't be able to use extends with recursivity because of how rabl-rails works. Since templates are "compiled" into plain ruby objects without any context, the break condition will never be evaluated, hence the stack error.

But we could imagine a new directive extends_recursive "some_template", ->(obj) { break condition }) that would delegate extends replacement at rendering time unless the break condition is met.