nathanvda / cocoon

Dynamic nested forms using jQuery made easy; works with formtastic, simple_form or default forms
http://github.com/nathanvda/cocoon
MIT License
3.09k stars 383 forks source link

How do I pass local variable to nested-field partial? #566

Closed jrmcchesney closed 5 years ago

jrmcchesney commented 5 years ago

<%= render 'question_fields', f: builder, counter: counter %>

I use counter in partial to make a label number. Doesn't work. Says counter is undefined? Confused because this is how I have always passed variables to partials?

Any help greatly appreciated. Thx

nathanvda commented 5 years ago

You are giving very little context, for a question that seems to be related to a pure ruby/rails question. Yes this is the correct form to pass local variables to a partial. Maybe the variable counter is undefined on this line? (as you give no clue on which line the error occurs, it could also be this line?)

jrmcchesney commented 5 years ago
<%= simple_form_for(@todo_list) do |f| %>
  <%= f.error_notification %>
  <%= f.error_notification message: f.object.errors[:base].to_sentence if f.object.errors[:base].present? %>

  <div class="form-inputs">
    <%= f.input :name %>
  </div>

  <table class="table">
    <thead>
      <tr>
        <th></th>
        <th>Task Name</th>              
      </tr>
    </thead>
    <tbody class="tasks">
      <%= f.simple_fields_for :tasks do |builder| %>
        <%= render 'task_fields', f: builder, dummy: "ww" %>
      <% end %>
    </tbody>
  </table>

  <div class="form-actions">
    <%= f.button :submit %>
    <%= link_to_add_association 'Add Task', f, :tasks, class: 'btn btn-primary', data: {
        association_insertion_node: '.tasks', association_insertion_method: :append} %>
  </div>
<% end %>

_task_fields partial

<tr class="nested-fields">
    <td>
         <%=dummy%><%= link_to_remove_association "remove task", f, 
         class: "btn btn-primary btn-xs" %>
    </td>
    <td><%= f.input :name, label: false %></td>

</tr>

Error:

undefined local variable or method `dummy' for #<#<Class:0x007fe35f91ed40>:0x007fe35e419288>

I stuck on why dummy can't be passed to the task_fields partial.
When I remove dummy everything works. I'm feeling like a dummy now.
Thanks for getting back to me and any help you can provide.

nathanvda commented 5 years ago

This is weird, because it does not give the same error for the f right? (if you omit the dummy in the render line?). Is this actual code or an example to clarify?

The render has two forms, either you write (compact form, available since rails 3+)

render 'partial_name', f: builder, dummy: "ww"

and then all extra parameters (f/dummy) are considered locals. But you can also make this more explicit, using

render partial: 'partial_name', locals: {f: builder, dummy: "ww"} 

(which should work in all rails versions).

See documentation: https://api.rubyonrails.org/classes/ActionView/PartialRenderer.html

jrmcchesney commented 5 years ago

Correct. This is actual code. the local f: works fine when I remove local "dummy". I wanted to just insert a counter in front of the list item so the nested items would have a number. I'm using rails 5.2.3 and simple_form gem. Strange.

nathanvda commented 5 years ago

Very weird. It makes no sense that one works and one not. Probably we are looking at this problem in the wrong way. Do you have a github repository for me to check, or a github repository with a minimal example reproducing the error so I can check?

jrmcchesney commented 5 years ago

jrmcchesney/mac_tutor is the public repository where I've been trialing this. Go to todo_lists. Remove the <%=counter %> in the task_fields partial and every thing works.

Thanks for all the help! ruby 2.4.0 is the version i'm using and I believe Rails 5.2.3

nathanvda commented 5 years ago

Aaarrgggghhh it took me a while to realise: the link_to_add_association also renders the partial, and it has not defined a value for counter. There are two possible solutions, either you fix the link_to_add_association:

<%= link_to_add_association 'Add Task', f, :tasks, class: 'btn btn-primary', data: {
        association_insertion_node: '.tasks', association_insertion_method: :append}, render_options: {locals: {counter: 'WW'}} %>

or you make your partial a little more robust, by adding this at the top:

<%- counter = "XX" unless local_assigns.has_key?(:counter) %>

Now if you just want to add a "row"-counter, which is not stored in the database, you could also just use css for that. Otherwise you will have to resort to using the cocoon callbacks to set the counter value correctly. Also see here: https://github.com/nathanvda/cocoon/issues/321#issuecomment-147346836

jrmcchesney commented 5 years ago

Thank You!! I went with your first suggestion and changed the link_to_add_association. I had viewed the docs and came close to your solution. I appreciate your time and wonderful gem. I am building a online High School Math quiz generator and cocoon has added some really nice-looking functionality.

Thanks again.

nathanvda commented 5 years ago

Great you found a solution :+1: :+1: