2つのモデルがあります。
-Parent
has_manyChildren
;
-Parent
accepts_nested_attributes_forChildren
;
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
に追加して、それが最後のものであるかどうかを確認することです。ただし、システムが複雑になります。
これはおそらくあなたのために働くでしょう、しかし私はそこにはるかに良い答えがあると感じています。それは私にはバグのように聞こえます。
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
バグではありません。ドキュメントによると
指定された属性が空白ではないことを検証します(Object#blank?で定義)。
validates :children, :presence => true
はまったく同じです。ドキュメントには、アソシエーションで使用しようとするとどうなるかは記載されていません。 validate
を使用したカスタム検証を使用する必要があります。
validates_presence_of
関連付けでhas_many
を使用すると、クラスアレイのオブジェクトである関連付けchildren
でblank?
が呼び出されます。 blank?
はArray
に対して定義されていないため、Rails内でキャッチされたmethod_missing
を起動します。通常、それはあなたが望むことをしますが、私はそれがRails 3.1rcとRuby 1.8.7で本当にひどい方法で失敗することを発見しました:それは静かにの変更を元に戻します何が起こっているのかを知るのに数時間かかりました。