Reputation: 535
I have an CEvemt model which has an association to Schedule model, now I'm trying to implement a form with multiple schedule objects: an user can add more schedule fields if he clicks the "Add more" link.
My form code:
<% 3.times do |x| %>
<%= render :partial => "schedule_field", :locals => {:event => @schedule} %>
<% end %>
<%= hidden_field_tag :schedule_fields_count, 2 %>
<%= link_to "Add more", "#", :id => "add_schedule_field" %>
partial:
<%= fields_for :event, event.schedules.build do |s| %>
<div class="row">
<div class="small-3.5 columns">
<%= s.datetime_select :start %>
</div>
<div class="small-3.5 columns">
<%= s.datetime_select :finish %>
</div>
<div class="small-5 columns">
<%= s.text_field :description %>
</div>
</div>
<% end %>
and for load more I use this view
$("#schedule_fields").
append("<%= escape_javascript(render :partial => 'schedule_field', :locals => {:event => @event}) %>");
$("#schedule_fields_count").val("<%= @number %>");
The problem is that this code doesn't render what I want.. For example on form I have 3 schedule description fields which all have the same name schedule[description]
, so the date is incorrect and I can't save it.
Upvotes: 1
Views: 2193
Reputation: 44715
Firstly, you need following line in your model:
accepts_nested_attributes_for :schedules
This line will define a setter schedules_attributes=
which will be later used in your form. You might want to pass some extra options like allow_destroy: true
or reject_if: :all_blank
.
Following lines:
<% 3.times do |x| %>
<%= render :partial => "schedule_field", :locals => {:event => @schedule} %>
<% end %>
with partial are incorrect. You need to call field_for
only once, and it should be called on your current form builder object. Instead do:
<%= f.fields_for :schedules do |s| %>
<%= render 'schedule_fields', f: s %>
<%= link_to "Add more", "#", :id => "add_schedule_field" %>
<% end %>
fields_for
will check whether object associated with form_builder
implements schedules_attributes=
setter (created by accepts_nested_attributes_for
method) and will behave accordingly.
Note: you do not need to specify partial:
in render - this is a default inside a view. I would rename your partial to schedule_fields
to use it with cocoon, but I'll get to it later. Your partial should only contains fields without fields_for
call:
<div class="row">
<div class="small-3.5 columns">
<%= f.datetime_select :start %>
</div>
<div class="small-3.5 columns">
<%= f.datetime_select :finish %>
</div>
<div class="small-5 columns">
<%= f.text_field :description %>
</div>
</div>
Building new objects should be placed in your controller, not in your view (as otherwise you won't be able to use the same partial for editing existing schedules). So in your controller do sth like:
(3 - @user.schedules.count).times { @user.schedules.build }
This will ensure you always have at least 3 schedules to display.
This should do it. As a lest step I would advise you to look at mentioned above coccon
gem. It is quite powerful tool for client side association creation and deletion. You can read about it here: https://github.com/nathanvda/cocoon
Upvotes: 1