任何人都知道如何在一个表单中保存许多对象?

时间:2010-10-19 14:17:36

标签: ruby-on-rails forms model nested-forms

我正在尝试将表单中的许多对象保存到一个预先存在的父对象。

- form_for :parent_object do |f|

这是我表格的开头。然后在其中,我会这样做:

  - 2.times do
    - fields_for :child_object do |f|

现在,如果我要保存它,它将呈现为 ParentObject_Controller 更新操作,该操作将失败,因为Update无法识别新对象。

因此,如果我想渲染相应的Save操作,我必须设置如下:

- form_for [@parent_object, @child_object] do |f|
  - 2.times do
    - fields_for :child_object do |f|

此表单随后呈现“保存”操作,但保存最后一个child_object。

我会告诉你我的控制器,但几乎没有意义,因为它具有毁灭性的错误。

我的问题是,如何将表单中的许多对象保存到一个预先存在的父对象?

我已经广泛关注了Ryan Bate的工作,以及许多其他博客和SO帖子。似乎没有什么能真正指出为一个预先存在的父对象专门创建新的子对象。

更新

我的印象是我必须为def update切换parent_object的控制器操作。

  elsif params[:parent_object][:child_object]
    @child_object = Child_Object.new(params[:child_object])
    if @child_object.valid? && @parent_object.referrals << @child_object
      redirect_to new_parent_object_child_object_path(@parent_object)
    else
      render :action => :new
    end

在调试器中,如果我将调试器放在def update的根目录下,我写道:

>> params[:parent_object]
#=> nil

有趣!这意味着当child_object被发送到parent_object控制器时,params不会被填充。哈哈,虽然不知道该怎么办..

不幸的是,代码不起作用,只是我试图靠近。 ;)

2 个答案:

答案 0 :(得分:1)

好的,让我们再试一次。代码取自RB's screencast的替换对象名称:

<% form_for @parent_object do |f| %>  
  <%= f.error_messages %>  
  <!-- some field of parent object here -->
  <p>  
    <%= f.label :name %><br />  
    <%= f.text_field :name %>  
  </p>  
  <% f.fields_for :child_objects do |builder| %>  
  <!-- some fields for child objects -->
  <p>  
    <%= builder.label :content, "Some content for child object" %><br />  
    <%= builder.text_area :content, :rows => 3 %>  
    <%= builder.check_box :_destroy %>  
    <%= builder.label :_destroy, "Remove child object" %>  
  </p>  
  <% end %>  
  <p><%= f.submit "Submit" %></p>  
<% end %>

这是@parent_object的表单,其中包含:child_objects的字段。当然,你要用自己的字段替换字段。

要使其工作,您必须在构造函数中构建子对象:

def new  
  @parent_object = ParentObject.new  
  3.times { @parent_object.child_objects.build }  
end 

同样在edit方法中,您可以:

def edit  
  @parent_object = ParentObject.find(params[:id])
  3.times { @parent_object.child_objects.build }  
end

要使其工作,您需要为子对象定义嵌套属性:

class ParentObject < ActiveRecord::Base  
  has_many :child_objects, :dependent => :destroy  
  accepts_nested_attributes_for :child_objects
end    

希望这会有所帮助 - 这正是RB在他的截屏视频中提出的建议。如果您需要进一步解释,请在评论中告诉我。

- 编辑 -

parent_object_controller.rb中的更新方法只是一个标准的方法:

def update
  @parent_object = ParentObject.find(params[:id])
  if @parent_object.update_attributes(params[:parent_object])
    flash[:notice] = "Successfully updated parent object."
    redirect_to @parent_object
  else
    render :action => 'edit'
  end
end

但是由于ParentObject中的accepts_nested_attributes_for,也会创建嵌套实例。

我没有在此响应中包含所有模型和控制器代码。您可以通过从github下载source code for this episode来查看其余代码。

答案 1 :(得分:0)

您可以查看this answer我给出的类似问题。有两种选择:使用单独的表单,或使用单一表单。

您只需将moderate_names_path更改为父模型实例的正确路径(当然还有您要修改的字段集)。您可以使用polymorphic_path

执行此操作
polymorphic_path([@parent_object, @child_object])