How to pass multiple locals to a nested partial

2019-04-11 20:13发布

This should be extremely straightforward and well documented, and I've done it several times, although there's something that's still killing me.

I have a structure of partials calling nested partials.

At some point one render call needs to pass an extra variable to the partial, although the rendering of the partial fails with a:

undefined local variable or method `<variable name>' for #<#<Class:....>

Here's my code for calling the render:

= f.simple_fields_for :orders do |c|
  = render partial: "fields", locals: {f: c, step: f.object.step}

though this doesn't work either:

= f.simple_fields_for :orders do |c|
  = render "fields", f: c, step: f.object.step

here's where the exception is raised:

f.input :quantity, input_html: {step: step}

the form_for comes from the views/lists/_form.html.haml:

= simple_form_for( @order, :html => { :multipart => true }, defaults: { input_html: { class: 'input-medium' } } ) do |f|

f is then passed to views/orders/_order_forms.html via

= render "orders/order_forms", f: f

here's the exception with trace:

    ActionView::Template::Error (undefined local variable or method `step' for #<#<Class:0x007fe0479ba2b0>:0x007fe04256a930>):

application trace:
    app/views/orders/_fields.html.haml:9:in `_app_views_orders__fields_html_haml___1860431911739668171_70300581339300'
    app/views/orders/_order_forms.html.haml:30:in `_app_views_orders__order_forms_html_haml__2241963939037094859_70300612771460'
    app/views/lists/_form.html.haml:48:in `block in _app_views_lists__form_html_haml__1669043093238943449_70300583658680'
    app/views/lists/_form.html.haml:3:in `_app_views_lists__form_html_haml__1669043093238943449_70300583658680'
    app/views/lists/new.html.erb:3:in `_app_views_lists_new_html_erb___1563391577928218041_70300593681100'
    app/controllers/lists_controller.rb:67:in `new'

framework trace (the end of it):

actionpack (3.2.8) lib/action_view/template.rb:145:in `block in render'
activesupport (3.2.8) lib/active_support/notifications.rb:125:in `instrument'
actionpack (3.2.8) lib/action_view/template.rb:143:in `render'
actionpack (3.2.8) lib/action_view/renderer/partial_renderer.rb:265:in `render_partial'
actionpack (3.2.8) lib/action_view/renderer/partial_renderer.rb:238:in `block in render'
actionpack (3.2.8) lib/action_view/renderer/abstract_renderer.rb:38:in `block in instrument'
activesupport (3.2.8) lib/active_support/notifications.rb:123:in `block in instrument'
activesupport (3.2.8) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
activesupport (3.2.8) lib/active_support/notifications.rb:123:in `instrument'
actionpack (3.2.8) lib/action_view/renderer/abstract_renderer.rb:38:in `instrument'
actionpack (3.2.8) lib/action_view/renderer/partial_renderer.rb:237:in `render'
actionpack (3.2.8) lib/action_view/renderer/renderer.rb:41:in `render_partial'
actionpack (3.2.8) lib/action_view/helpers/rendering_helper.rb:27:in `render'
haml (4.0.3) lib/haml/helpers/action_view_mods.rb:10:in `block in render_with_haml'
haml (4.0.3) lib/haml/helpers.rb:89:in `non_haml'
haml (4.0.3) lib/haml/helpers/action_view_mods.rb:10:in `render_with_haml'
cocoon (1.2.0) lib/cocoon/view_helpers.rb:40:in `block in render_association'

I've had a similar issue before and I resolved it in simplifying the passing of locals.. but now I would really like to understand what's going on.

any clue?

I'm using:

ruby 2.0.0p297
rails 3.2.8

Thanks a lot in advance..

UPDATE

I have debugged my view and figured that the order_forms is being rendered twice, the first time step is not set, while in the second rendering it is set correctly.

I'm not sure why this happens, but I managed to work it around with adding the following line to my fields.html.haml.

-step = step || 1

basically I put a default value to step, in case it's not defined, so that at the first execution the rendering doesn't crash, while at the second execution it works properly.

The page looks as expected now. Although I'm thinking about the waste of resources when rendering the stuff twice.

any idea on why that happens?

1条回答
等我变得足够好
2楼-- · 2019-04-11 20:21

After finding out that the code was run twice, I went investigating who else was running it.

and I realized that just few lines before there was the call to cocoon function link_to_add_association

of course it's not only the official render rendering the partial but also that function needs to render it.

I have added the line:

:render_options => {:locals => {:step => step }},

to my link_to_add_association function call and removed the workaround and now everything works as expected.

The more modern version analogous to this would be:

render_options: {locals: {step: step }},

a bit shorter, and looking better.

查看更多
登录 后发表回答