2011-02-28 37 views
38

Tôi có hai kiểu máy.
- Parenthas_manyChildren;
- Parentchấp nhận_nested_attributes_forChildren;Mô hình lồng nhau và xác thực của phụ huynh

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 

Tôi sử dụng xác thực để xác thực sự hiện diện của trẻ em cho mọi phụ huynh, vì vậy tôi không thể lưu cha mẹ không có con.

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

xác thực hoạt động. Sau đó chúng tôi sẽ hủy con qua _destroy thuộc tính:

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

vì vậy tôi có thể phá hủy tất cả trẻ em thông qua các hình thức lồng nhau và xác nhận sẽ vượt qua.

Trên thực tế điều đó xảy ra vì sau khi tôi xóa trẻ em từ cha mẹ của tôi qua _delete, trẻ em phương pháp vẫn trả về phá hủy đối tượng trước khi tôi tải lại nó, vì vậy xác nhận thông qua:

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

Có lỗi?

Câu hỏi là gì. Câu hỏi là giải pháp tốt nhất để sửa chữa nó. Cách tiếp cận của tôi là thêm bộ lọc before_destroy vào Child để kiểm tra xem bộ lọc có phải là bộ lọc cuối cùng hay không. Nhưng nó làm cho hệ thống phức tạp.

Trả lời

57

Điều này có thể phù hợp với bạn, nhưng tôi có cảm giác có một câu trả lời tốt hơn nhiều ở đó. Nghe có vẻ như là một lỗi đối với tôi.

class Parent 
    validate :must_have_children 

    def must_have_children 
    if children.empty? or children.all? {|child| child.marked_for_destruction? } 
     errors.add(:base, 'Must have at least one child') 
    end 
    end 
end 
+0

tuy nhiên nó sẽ tốt hơn sau đó xác nhận về 'bên Child' :) nhờ – fl00r

+2

và nhờ cho 'marked_for_destruction?' – fl00r

+0

phương pháp xác nhận này vẫn yêu cầu như của Rails 3.0.6 – astjohn

0

Nó không phải là lỗi. Theo cách tài liệu

Xác nhận rằng quy định thuộc tính này là không trống (theo quy định bởi Object # trống?)

validates :children, :presence => true chỉ là giống nhau. Tài liệu không nói điều gì sẽ xảy ra nếu bạn cố gắng sử dụng nó trên một liên kết. Bạn nên sử dụng xác thực tùy chỉnh bằng cách sử dụng validate.

Sử dụng validates_presence_of trên has_many các cuộc gọi liên kết blank? về liên kết children, là đối tượng của lớp Array. Vì số blank? không được xác định cho một số Array, nó sẽ kích hoạt method_missing được phát hiện bên trong Rails. Thông thường nó làm những gì bạn muốn nhưng tôi thấy nó thất bại trong Rails 3.1rc và Ruby 1.8.7 một cách thực sự khủng khiếp: nó âm thầm reverts những thay đổi của hồ sơ liên quan. Tôi mất một vài giờ để tìm hiểu điều gì đang xảy ra.

+2

Trên thực tế vấn đề bởi vì nó vaidates sự hiện diện của trẻ em TRƯỚC KHI loại bỏ trẻ em.Vì vậy, chúng ta nên kiểm tra xem trẻ em có phải là 'marker_for_destruction không? ' – fl00r

Các vấn đề liên quan