Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

self-referential templates blow up rake task but not server #18667

Open
jjb opened this issue Jan 23, 2015 · 11 comments
Open

self-referential templates blow up rake task but not server #18667

jjb opened this issue Jan 23, 2015 · 11 comments

Comments

@jjb
Copy link
Contributor

jjb commented Jan 23, 2015

I have two partials which refer to one another. When I calculate nested dependencies in the console like so:

finder = ApplicationController.new.lookup_context
ActionView::Digestor.new(name: "posts/show", finder: finder).nested_dependencies

or via the rake task like so:

rake cache_digests:nested_dependencies TEMPLATE=posts/show

I get a short list of initial dependencies, and then this in an infinite loop, until the ruby stack is full (I have some debug code outputting which template is being loaded):

...
>>>>>>> users/foo
>>>>>>> users/bar
>>>>>>> users/baz
>>>>>>> users/bip
>>>>>>> users/foo
>>>>>>> users/bar
>>>>>>> users/baz
>>>>>>> users/bip
SystemStackError: stack level too deep

However, when I run the app server and request the template, things run just fine, no infinite loops.

Here are my settings in all of the above cases:

config.action_controller.perform_caching = true
config.cache_store = :file_store, Rails.root.to_s + '/tmp/cache/stuff'
ActionView::Base.cache_template_loading = true

The code indicates that it does have recursive reference protection: https://github.com/rails/rails/blob/v4.1.8/actionview/lib/action_view/digestor.rb#L35

I'm not really groking that code. It seems like the recursive reference protection is working in the server environment but not in console or the rake task.

(also a SO question http://stackoverflow.com/questions/28018187)

@jjb
Copy link
Contributor Author

jjb commented Jan 23, 2015

(i'm putting together a PoC rails app)

@jjb
Copy link
Contributor Author

jjb commented Jan 24, 2015

Here is the repo: https://github.com/jjb/rails-18667

All the relevant files are in this commit: jjb/rails-18667@5b1fa9a

To observe the infinite loop:

rake cache_digests:nested_dependencies TEMPLATE=things/index

To observe that nested dependency calculation is working and not blowing up when the server is running:

  1. watch for number of cache objects in one terminal

    rm -rf tmp/cache/objects
    mkdir tmp/cache/objects
    watch 'ls -1 tmp/cache/objects | wc -l'
  2. start rails server in another terminal

  3. curl http://localhost:3000/things in a third terminal

  4. note the number of cache objects in the first terminal. it should be 3

  5. change index.html.erb (just add "hello" to the end or something)

  6. run the curl command again. note that only one cache object needed to be rebuilt. the number is up to 4.

  7. change either _foo.html.erb or _bar.html.erb. not both!

  8. run the curl command again. note the number of cache objects has increased by 3 and is now 7. So, rails correctly figured out that all three templates depend on one another.

(n.b. if you change any of the files back to a previous state, rails will reuse the previously built cache. this might be confusing if you are toggling back and forth between states and expecting the number to keep increasing.)

@jjb
Copy link
Contributor Author

jjb commented Jan 24, 2015

@jiripospisil a new bug, see above

@jiripospisil
Copy link
Contributor

@jjb It seems like the protection against recursion is not used in the code path invoked by #nested_dependencies. Try changing it to this. I'm not sure if it's the right solution in general though, more precisely, I'm not sure what the result should even look like if there's more than one nested template calling each other recursively.

@jjb
Copy link
Contributor Author

jjb commented Jan 24, 2015

@jiripospisil which version of rails did you base your method on? it has a different signature than the one in 4.1.8

@jiripospisil
Copy link
Contributor

@jjb You mean the processed argument? That's just because I was being lazy and reused the same method for the recursion. It does have a default value so there shouldn't be any compatibility breaks. In the real code, we'll probably want to keep the signature intact and delegate to an internal method.

@jjb
Copy link
Contributor Author

jjb commented Jan 25, 2015

ahh, gotcha.

@jjb
Copy link
Contributor Author

jjb commented Jan 25, 2015

@rafaelfranca @tvdeyen any thoughts on making the rake task's behavior more in line with in-app behavior? if we all agree this is not ideal I can work on a PR, just making sure I'm headed in the right direction first.

@rails-bot
Copy link

This issue has been automatically marked as stale because it has not been commented on for at least
three months.

The resources of the Rails team are limited, and so we are asking for your help.

If you can still reproduce this error on the 4-2-stable, 4-1-stable branches or on master,
please reply with all of the information you have about it in order to keep the issue open.

Thank you for all your contributions.

@jjb
Copy link
Contributor Author

jjb commented Jun 26, 2015

I did reproduce it above: #18667 (comment)

@rafaelfranca
Copy link
Member

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants