嵌套模型和父级验证

fl0*_*00r 40 ruby ruby-on-rails nested-attributes

我有两个型号.
- Parent has_many Children ;
- Parent accepts_nested_attributes_for Children ;

class Parent < ActiveRecord::Base
  has_many :children, :dependent => :destroy
  accepts_nested_attributes_for :children, :allow_destroy => true
  validates :children, :presence => true
end

class Child < ActiveRecord::Base
  belongs_to :parent
end
Run Code Online (Sandbox Code Playgroud)

我使用验证来验证每个父母的孩子的存在,所以我不能保存没有孩子的父母.

parent = Parent.new :name => "Jose"
parent.save
#=> false
parent.children_attributes = [{:name => "Pedro"}, {:name => "Emmy"}]
parent.save
#=> true
Run Code Online (Sandbox Code Playgroud)

验证工作.然后我们将通过_destroy属性摧毁孩子:

parent.children_attributes = {"0" => {:id => 0, :_destroy => true}}
parent.save
#=> true !!!
parent.reload.children
#=> []
Run Code Online (Sandbox Code Playgroud)

所以我可以通过嵌套表单销毁所有孩子,验证将通过.

实际上发生这种情况是因为在我从父进程中删除子_delete进程之后,在重新加载之前,children方法仍然返回被破坏的对象,因此验证通过:

parent.children_attributes = {"0" => {:id => 0, :_destroy => true}}
parent.save
#=> true !!!
parent.children
#=> #<Child id:1 ...> # It's actually deleted
parent.reload.children
#=> []
Run Code Online (Sandbox Code Playgroud)

是bug吗?

问题是什么?问题是修复它的最佳解决方案.我的方法是添加before_destroy过滤器Child来检查它是否是最后一个.但它使系统变得复杂.

Joh*_*hat 60

这可能对你有用,但我觉得那里有更好的答案.这对我来说听起来像个错误.

class Parent < ActiveRecord::Base
  validate :must_have_children

  def must_have_children
    if children.empty? || children.all?(&:marked_for_destruction?)
      errors.add(:base, 'Must have at least one child')
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

  • 快速一行:`errors.add(:base,'必须至少有一个孩子')如果children.all?(&:marked_for_destruction?)`.谢谢你! (12认同)
  • 你不需要`children.empty?或者`part因为`children.all?`总是为空集合返回`true` (4认同)