2012-04-06 20 views
6

Có cách nào để kiểm tra, trong móc before_destroy, đối tượng (lớp) nào được gọi là destroy?has_many thông qua hủy diệt phụ thuộc vào hiệp hội trong điều kiện ai được gọi là hủy

Trong ví dụ sau, khi patient bị hủy, vậy hãy là appointments (đó là điều tôi muốn); tuy nhiên tôi không muốn cho phép physician bị hủy nếu có bất kỳ appointments nào được liên kết với số physician đó.

Một lần nữa, có cách nào để thực hiện việc kiểm tra như vậy trong số gọi lại before_destory không? Nếu không, có cách nào khác để thực hiện "kiểm tra hủy diệt" này dựa trên "hướng" của cuộc gọi (tức là dựa trên người được gọi) không?

class Physician < ActiveRecord::Base 
    has_many :appointments, dependent: :destroy 
    has_many :patients, through: :appointments 
end 


class Patient < ActiveRecord::Base 
    has_many :appointments, dependent: :destroy 
    has_many :physicians, through: :appointments 
end 


class Appointment < ActiveRecord::Base 
    belongs_to :patient 
    belongs_to :physician 

    before_destroy :ensure_not_referenced_by_anything_important 

    private 

    def ensure_not_referenced_by_anything_important 
    unless patients.empty? 
     errors.add(:base, 'This physician cannot be deleted because appointments exist.') 
     false 
    end 
    end 
end 

Trả lời

11

Chỉ cần nói:

class Physician < ActiveRecord::Base 
    has_many :appointments, dependent: :restrict_with_exception 
    has_many :patients, through: :appointments 
end 

Lưu ý dependent: :restrict_with_exception. Điều này sẽ khiến cho Active Record từ chối hủy bất kỳ hồ sơ Bác sĩ nào có hồ sơ Chỉ định liên quan.

Xem the API docsthe association basics guide.

+0

[': restrict' không được dùng nữa] (https://github.com/rails/rails/commit/5ad79989ef0a015fd22cfed90b2e8a56881e6c36#diff-5870816b49b90e43340607bb11ed2514R91) Ngày 10 tháng 8 năm 2012 trong một chi nhánh được đặt cho' Rails 4'. [Hướng dẫn * khái niệm cơ bản về hiệp hội cũng đã được cập nhật] (https://github.com/rails/rails/commit/a63fc94aa3689f1e781ac51411ec79a81c011d8a). ': restrict_with_exception' cung cấp cùng chức năng như': limits' đã làm; cũng có một tùy chọn tương tự khác, ': restrict_with_error', làm cho lỗi được thêm vào chủ sở hữu nếu có một đối tượng liên kết. – user664833

15

Lưu ý rằng dependent: :destroy vào một mối quan hệ has_many :through chỉ xóa các hiệp hội và không kỷ lục liên quan (ví dụ: các hồ sơ tham gia sẽ bị xóa, nhưng các hồ sơ có liên quan sẽ không). Vì vậy, nếu bạn xóa patient, nó sẽ chỉ xóa appointment chứ không phải physician. Đọc phần giải thích chi tiết trong the API docs.

Tôi đã dán các đoạn có liên quan bên dưới.

Điều gì sẽ bị xóa?

Có một sự cố tiềm ẩn ở đây: has_and_belongs_to_manyhas_many :through các liên kết có bản ghi trong bảng tham gia, cũng như các bản ghi liên quan. Vì vậy, khi chúng tôi gọi một trong những phương pháp xóa này, chính xác những gì sẽ bị xóa?

Câu trả lời là người ta cho rằng việc xóa liên kết là loại bỏ liên kết giữa chủ sở hữu và (các) đối tượng liên quan, thay vì nhất thiết là các đối tượng được liên kết. Vì vậy, với has_and_belongs_to_manyhas_many :through, hồ sơ tham gia sẽ bị xóa nhưng các bản ghi được liên kết sẽ không bị xóa.

này có ý nghĩa nếu bạn nghĩ về nó: nếu bạn đã gọi post.tags.delete(Tag.find_by_name('food')) bạn muốn tag food được hủy liên kết khỏi post, chứ không phải cho thẻ tự phải được loại bỏ khỏi cơ sở dữ liệu.

+0

Giải thích tuyệt vời, Cảm ơn! Tôi đã có một thời gian khó khăn để tìm ra nếu phụ thuộc:: phá hủy xóa các hiệp hội và các hồ sơ ở phía bên kia. – Arel

+0

Điều này có vẻ như một câu trả lời kỹ lưỡng, tuy nhiên, tôi đã thiết lập nó như bạn đã nói và khi tôi cố gắng xóa một bệnh nhân (sử dụng quản trị đường ray), bác sĩ cũng bị loại bỏ. –