rails fields_for嵌套对象

时间:2014-01-11 13:03:14

标签: ruby-on-rails

我有一个与Schedule模型关联的CEvemt模型,现在我正在尝试实现一个包含多个计划对象的表单:如果用户单击“添加更多”链接,则可以添加更多计划字段。

我的表单代码:

<% 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" %>

部分:

<%= 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 %>

对于加载更多我使用此视图

$("#schedule_fields").
  append("<%= escape_javascript(render :partial => 'schedule_field', :locals => {:event => @event}) %>");

$("#schedule_fields_count").val("<%= @number %>");

问题是这段代码没有呈现我想要的东西..例如在表单上我有3个日程表描述字段,它们都具有相同的名称schedule[description],所以日期不正确我不能保存它。

1 个答案:

答案 0 :(得分:1)

首先,您需要在模型中使用以下行:

accepts_nested_attributes_for :schedules

此行将定义一个稍后将在您的表单中使用的setter schedules_attributes=。您可能希望传递一些额外的选项,例如allow_destroy: truereject_if: :all_blank

以下行:

<% 3.times do |x| %>
  <%= render :partial => "schedule_field", :locals => {:event => @schedule} %>
<% end %>

部分不正确。您只需要调用field_for一次,并且应该在当前的表单构建器对象上调用它。而是做:

<%= f.fields_for :schedules do |s| %>
  <%= render 'schedule_fields', f: s %>
  <%= link_to "Add more", "#", :id => "add_schedule_field" %>
<% end %>

fields_for将检查与form_builder相关联的对象是否实现了schedules_attributes= setter(由accepts_nested_attributes_for方法创建)并且会相应地执行。 注意:您不需要在渲染中指定partial: - 这是视图中的默认值。我会将你的部分重命名为schedule_fields并将它与茧一起使用,但我会在以后再说。您的部分应该只包含没有fields_for调用的字段:

<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>

构建新对象应放在控制器中,而不是放在视图中(否则您将无法使用相同的部分来编辑现有的日程表)。所以在你的控制器中做某事:

(3 - @user.schedules.count).times { @user.schedules.build }

这将确保您始终至少有3个时间表可供显示。

这应该这样做。作为一个最好的步骤,我建议你看看上面提到的coccon宝石。它是用于创建和删除客户端关联的非常强大的工具。您可以在此处阅读:https://github.com/nathanvda/cocoon