使用accepts_nested_attributes_for时获取父级

时间:2013-07-30 19:57:35

标签: ruby-on-rails associations

收到时:

{
   parent:{
      children_attributes:[
        {child1}, {child2}
      ]
   }
}

即将创建child1个实例,我没有设置parent_id。我想这是在节省时间设置的。

我该如何处理这个问题:

class Child < ActiveRecord::Base
  belongs_to :parent
  before_save :do_something

  def do_something
    # access parent here
    # I can't, since parent_id is nil yet
  end
end

更新更清晰

class Parent <  ActiveRecord::Base
  has_many :children
  accepts_nested_attributes_for :children
end

更新2

我是通过相关问题尝试过的:

class Parent <  ActiveRecord::Base
  has_many :children, inverse_of: :parent
end

但同样的问题。

根据评论更新3

我试过这个

class Parent
  before_save :save_children
  attr_accessor :children_attributes

  def save_children
    children_attributes.all? do |k, attrs|
      # tried different things here, this one is the one I expected to work the most 
      child = Child.new attrs.merge(parent_id: id)
      child.save
    end
  end

我将parent_id添加到子attr_accessible调用。

我错过了什么?

4 个答案:

答案 0 :(得分:2)

这个问题的原因是验证了子类中父项的存在。

我基本上从Child对象中删除了这一行,它可以正常工作。

validates :parent, presence: true

但是,根据我的发现,解决此问题的正确方法是使用inverse_of参数。如果您将其添加到父级的has_many和孩子的belongs_to,那么您应该很高兴。

在父母:

has_many :child, inverse_of: :parent

在孩子身上:

belongs_to :parent, inverse_of: :child

答案 1 :(得分:1)

在模型中的has_many声明中设置inverse_of: :model_name,其中model_name是您的“父”模型。

例如:has_many :product_items, dependent: :destroy, inverse_of: :product

答案 2 :(得分:0)

在你的模型中,你应该能够像这样引用父母:

self.parent_class

因此,例如,如果产品包含许多零件,则在零件模型(part.rb)中,您可以像这样引用产品的属性:

self.product.id

这将返回作为零件父级的产品的id。你可以显然像这样引用父类的任何属性。

这应该适用于子模型中的before_save回调。

此外,您不应该使用上面代码中包含的“inverse_of :: parent”来实现此目的。

要回答关于何时添加父ID的问题,如果您的表单设置正确,则应自动将表单中的参数传递给控制器​​。

答案 3 :(得分:0)

这可能对您的问题有所帮助:http://guides.rubyonrails.org/association_basics.html#association-callbacks

关联回调不适用于belongs_to,但适用于has_many

class Parent < ActiveRecord::Base
  has_many :children, before_add: :do_something

  def do_something(child)
    # self.id = 1
    # child.parent_id = 1
  end
end

# parent1 = Parent.find(1)
# parent1.children.create(...)