2014-01-11 100 views
1

我有一个CEvemt模型,它与Schedule模型有关联,现在我试图用多个计划对象实现一个表单:如果用户点击“添加更多”链接,用户可以添加更多计划字段。rails fields_for嵌套对象

我的表单代码:

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

首先,你需要在你的模型下面一行:

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=二传手(由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

+0

如果你有固定数量的字段,在这种情况下3,在这种情况下,你不能添加另一个新字段,因为你提供了部分表单对象 – maki

+0

你可以添加新字段用这种方法。 Fields_for将呈现每个关联对象的所有部分,表单构建器将处理这些对象。 – BroiSatse

+0

我的意思是你不能通过Ajax添加一个新的字段,或者我失去了一些东西? – maki