how to dynamically add nested attributes in rails with jquery

强颜欢笑 提交于 2019-12-08 09:55:04

问题


I've been asking iterations of this question for a while now - but with a lot of help from the SO community i've very nearly got it working. So first, thanks!

I have a form to create a new student_group and am using the Cocoon gem:

<%= form_for @student_group do |f| %>

  <p>
    The name of this group is 
    <span class="field form_field"><%= f.text_field :name %></span>
    and it is a/an 
    <span class="field dropdown"><%= f.select :type_of_group, [["select a group type", ""], "young learners class (0-6)", "primary class (7-12)", "secondary class (13-17)", "adult class (18+)", "children's sport team", "adult's sport team"]  %></span>       
  </p>

  <p>
    There are 
    <span id="nos" class="field dropdown"><%= f.select :number_of_students, (0..60) %></span>
    students in this group.   
  </p>


  <table id="students_form_table">
    <tbody>
      <!-- https://stackoverflow.com/questions/11445831/how-to-submit-multiple-new-items-via-rails-3-2-mass-assignment -->
      <%= f.fields_for :students, @student, child_index: @student do |builder| %>
        <%= render "student_fields", :f => builder %>
      <% end %>
    </tbody>    
  </table>

  <p>
    <%= f.submit "Submit", :class => 'big_button round unselectable'%>
  </p>

<% end %>

and the 'student_fields' partial:

<tr class="nested-fields">
  <td id="student_name" class="field form_field"><%= f.text_field :name, placeholder: "Student name" %></td>
  <td id="student_gender" class="field dropdown"><%= f.select :gender, [["select a gender", ""],'Female', 'Male', 'Transgender'] %></td>
  <td id="remove_link"><%= link_to_remove_association "remove student", f %></td>
</tr>

Now the heart of the question:

I have the following .js file to dynamically add the correct number of student fields to the form:

var row_i = 0;

function emptyRow() {
row_i++;
this.obj = $("<tr></tr>");
this.obj.append('<td id="student_name" class="field form_field"><input id="student_group_students_attributes___Student:0x00000103c4ead8__name" name="student_group[students_attributes][#&lt;Student:0x00000103c4ead8&gt;][name]" type="text" /></td>');
this.obj.append('<td id="student_gender" class="field dropdown"><select id="student_group_students_attributes___Student:0x00000103c4ead8__gender" name="student_group[students_attributes][#&lt;Student:0x00000103c4ead8&gt;][gender]"><option value="">select a gender</option><option value="Female">Female</option><option value="Male">Male</option><option value="Transgender">Transgender</option></select></td>');
this.obj.append(' <td id="remove_link"><input id="student_group_students_attributes___Student:0x00000103c4ead8___destroy" name="student_group[students_attributes][#&lt;Student:0x00000103c4ead8&gt;][_destroy]" type="hidden" /><a href="#" class="remove_fields dynamic">remove student</a></td>')
}

function refresh(new_count) {
  //how many students we have got?
  console.log("New count= " + new_count);
  if (new_count > 0) {
    $('#students_form_table').show();
  } 
  else {
    $('#students_form_table').hide();
  }

 var old_count = parseInt($('tbody').children().length);
   console.log("Old count= " + old_count);
   //calculates difference between rows needed/rows current
 var rows_difference = parseInt(new_count) - old_count;
   console.log("Rows diff= " + rows_difference);
   //if we have rows to add
 if (rows_difference > 0) {
   for (var i = 0; i < rows_difference; i++)
   $('tbody').append((new emptyRow()).obj);
 } else if (rows_difference < 0) //we need to remove rows ..
 {
   var index_start = old_count + rows_difference + 1;
   console.log("Index start= " + index_start);
   $('tr:gt(' + index_start + ')').remove();
   row_i += rows_difference;
 }
}

$(document).ready(function () {
  //hide table by default
  $('#students_form_table').hide();

  $('#nos').change(function () {
    var opt=$('#nos option:selected');
    refresh(opt.text());
  })

});

So this form very nearly works - everything formats correctly, and when I select 'x' number of students, 'x' number of student forms are built - however, because of this -

function emptyRow() {
  row_i++;
  this.obj = $("<tr></tr>");
  this.obj.append('<td id="student_name" class="field form_field"><input id="student_group_students_attributes___Student:0x00000103c4ead8__name" name="student_group[students_attributes][#&lt;Student:0x00000103c4ead8&gt;][name]" type="text" /></td>');
  this.obj.append('<td id="student_gender" class="field dropdown"><select id="student_group_students_attributes___Student:0x00000103c4ead8__gender" name="student_group[students_attributes][#&lt;Student:0x00000103c4ead8&gt;][gender]"><option value="">select a gender</option><option value="Female">Female</option><option value="Male">Male</option><option value="Transgender">Transgender</option></select></td>');
  this.obj.append(' <td id="remove_link"><input id="student_group_students_attributes___Student:0x00000103c4ead8___destroy" name="student_group[students_attributes][#&lt;Student:0x00000103c4ead8&gt;][_destroy]" type="hidden" /><a href="#" class="remove_fields dynamic">remove student</a></td>')
}

...the fields aren't being rendered correctly - in that they aren't creating discreet instances of new student fields. I understand that the problem is the hash in the id/name portion of the html generated by rails, but i'm not sure how to replace it so that this will work. the closest i've come is trying to adapt the coffeescript from this site, but I couldn't get it working.

So how to dynamically generate new forms for models using jquery?

EDIT: Actually I've just realized that the first and last forms will save properly - that is, if I add eight students, student1 and student8 will be entered into the database, but the others will not. this only confuses me more :/

EDIT 2: I've found this jquery api called 'serialize' in the context of this question and i think it might be what i need, but having trouble adapting it. Help me!


回答1:


Got it!

Tried out a lot of things but this is what worked in the end:

student_groups_controller.rb #create

def create
  @params = params[:student_group][:students_attributes]
  @student_group = @user.student_groups.build(params[:student_group])
    if @student_group.save
      ###   RE: 'defensive coding' http://stackoverflow.com/questions/14502508/undefined-method-for-nilnilclass-when-pushing-values-to-an-array  
      if @params.present?
        ### http://stackoverflow.com/questions/11355820/rails-3-2-iterate-through-an-array
        @params.each do |student|
          @student_group.students.create(name:"#{student[:name]}", gender: "#{student[:gender]}")
        end
      end    
      # new subject path
      redirect_to class_path(@student_group), flash: { success: "#{@student_group.name} has been added successfully" }   
    else
      @title = "Create a new group"
      flash.now[:error] = "Something's gone wrong.  Please try again!"
      render 'new' 
    end  
end

relevant section of _groups_form.html.rb

<table id="students_form_table">
  <tbody>
    <!-- http://stackoverflow.com/questions/11445831/how-to-submit-multiple-new-items-via-rails-3-2-mass-assignment -->
    <%= fields_for 'student_group[students_attributes][]', @student, index: nil do |builder| %>
        <%= render "student_fields", :f => builder %>
    <% end %>
    </tbody>    
</table>

and finally, the relevant portion of student_groups.js:

function emptyRow() {
  row_i++;
  this.obj = $("<tr></tr>");
  this.obj.append('<td id="student_name" class="field form_field"><input id="student_group_students_attributes__name" name="student_group[students_attributes][][name]" placeholder="Student name" size="30" type="text" /></td>');
  this.obj.append('<td id="student_gender" class="field dropdown"><select id="student_group_students_attributes__gender" name="student_group[students_attributes][][gender]"><option value="">select a gender</option><option value="Female">Female</option><option value="Male">Male</option><option value="Transgender">Transgender</option></select></td>');
  this.obj.append('<td id="remove_link"><input id="student_group_students_attributes___destroy" name="student_group[students_attributes][][_destroy]" type="hidden" /><a href="#" class="remove_fields dynamic">remove student</a></td>')
}


来源:https://stackoverflow.com/questions/17527384/how-to-dynamically-add-nested-attributes-in-rails-with-jquery

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!