【问题标题】:Nested models and parent validation嵌套模型和父验证
【发布时间】:2011-07-05 21:31:36
【问题描述】:

我有两个模型。
- 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

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

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
#=> []

是bug吗?

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

【问题讨论】:

    标签: ruby-on-rails ruby nested-attributes


    【解决方案1】:

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

    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
    

    【讨论】:

    • 尽管如此,在Child 方面进行验证会更好:) 谢谢
    • 自 Rails 3.0.6 起仍需要此验证方法
    • 你不需要 children.empty? or 部分,因为 children.all? 总是返回 true 用于空集合
    • 快速一班:errors.add(:base, 'Must have at least one child') if children.all?(&amp;:marked_for_destruction?)。谢谢你!
    【解决方案2】:

    这不是错误。根据文档

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

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

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

    【讨论】:

    • 实际上是问题所在,因为它在删除儿童之前验证了儿童的存在。所以我们应该检查孩子是否是marked_for_destruction?
    猜你喜欢
    • 2012-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-28
    相关资源
    最近更新 更多