43

私は2つのモデルを持っています。
- Parent has_many Children ;
- Parent accept_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リロードする前に children メソッドが破棄されたオブジェクトを返すため、検証に合格したために発生します。

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

クラス Array のオブジェクトであるassociationの関連付け呼び出しで使用validates_presence_ofします。に対して が定義されていないため、Rails内でキャッチされて発火します。通常、それはあなたが望むことを行いますが、Rails 3.1rc と Ruby 1.8.7 では本当にひどい方法で失敗することがわかりました。関連付けられたレコードの変更を黙って元に戻します。何が起こっているのかを知るのに数時間かかりました。has_manyblank?childrenblank?Arraymethod_missing

于 2011-05-31T02:32:15.180 に答える