43

我有两个模型。
- Parent has_many Children ;
-Parent 接受_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

我使用验证来验证每个父母是否存在孩子,所以我无法保存没有孩子的父母。

parent = Parent.new :name => "Jose"
parent.save
#=> false
parent.children_attributes = [{:name => "Pedro"}, {:name => "Emmy"}]
parent.save
#=> true

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

parent.children_attributes = {"0" => {:id => 0, :_destroy => true}}
parent.save
#=> true !!!
parent.reload.children
#=> []

所以我可以通过嵌套表单销毁所有孩子并且验证将通过。

实际上发生这种情况是因为在我通过删除父级的子级之后_delete,子级方法在我重新加载它之前仍然返回销毁的对象,因此验证通过:

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

是虫子吗?

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

4

2 回答 2

62

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

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
于 2011-02-28T16:42:22.043 回答
0

这不是一个错误。根据文档

验证指定的属性不为空(由 Object#blank? 定义)

并且validates :children, :presence => true是一样的。文档没有说明如果您尝试在关联上使用它会发生什么。您应该使用自定义验证使用validate.

validates_presence_of在关联上使用has_many关联调用blank?关联children,关联是类 Array 的对象。由于blank?没有为 a 定义,因此它会在 Rails 中Array触发。method_missing通常它会做你想做的事,但我发现它在 Rails 3.1rc 和 Ruby 1.8.7 中以一种非常糟糕的方式失败:它默默地恢复关联记录的更改。我花了几个小时才弄清楚发生了什么。

于 2011-05-31T02:32:15.180 回答