12

Như một ví dụ cho vấn đề dependent: :destroy tròn:Có phụ thuộc vòng tròn Rails 4:: phá hủy cách giải quyết không?

class User < ActiveRecord::Base 
    has_one: :staff, dependent: :destroy 
end 

class Staff < ActiveRecord::Base 
    belongs_to :user, dependent: :destroy 
end 

Nếu tôi gọi user.destroy, các liên staff nên bị hủy diệt là tốt. Ngược lại, gọi số staff.destroy cũng nên hủy liên kết user.

Điều này làm việc tuyệt vời trong Rails 3.x, nhưng hành vi đã thay đổi trong Rails 4.0 (và tiếp tục trong 4.1) sao cho một biểu mẫu vòng lặp và cuối cùng bạn gặp lỗi, "cấp độ quá sâu." Một giải pháp rõ ràng là tạo một cuộc gọi lại tùy chỉnh bằng cách sử dụng before_destroy hoặc after_destroy để hủy các đối tượng được liên kết theo cách thủ công thay vì sử dụng cơ chế dependent: :destroy. Ngay cả tình huống issue in GitHub opened for this cũng có một vài người đề xuất cách giải quyết này.

Thật không may, tôi thậm chí không thể có được giải pháp đó để hoạt động. Đây là những gì tôi có:

class User < ActiveRecord::Base 
    has_one: :staff 

    after_destroy :destroy_staff 

    def destroy_staff 
    staff.destroy if staff and !staff.destroyed? 
    end 
end 

Lý do này không làm việc là staff.destroyed? luôn trả false. Vì vậy, nó tạo thành một chu kỳ.

+0

bạn đã triển khai logic đó cho cả hai kiểu như Jken13579 đề xuất? – xlembouras

+0

@xlembouras, chưa thử, nhưng tôi chắc chắn nó sẽ không hoạt động. Tôi sẽ thử nó trong tuần này chỉ để chắc chắn. Tôi đã viết dưới đây lý do tại sao nó sẽ không hoạt động. –

+0

@at. bất kỳ may mắn với câu trả lời của tôi? –

Trả lời

2

Tôi cũng gặp sự cố này và đã đưa ra giải pháp không đẹp nhưng hiệu quả. Về cơ bản, bạn chỉ cần sử dụng một số destroy_user tương tự như destroy_staff.

class User < ActiveRecord::Base 
    has_one: :staff 

    after_destroy :destroy_staff 

    def destroy_staff 
    staff.destroy if staff && !staff.destroyed? 
    end 
end 

class Staff < ActiveRecord::Base 
    belongs_to :user 

    after_destroy :destroy_user 

    def destroy_user 
    user.destroy if user && !user.destroyed? 
    end 
end 
+0

Lạ, stackoverflow không cập nhật hộp thư đến của tôi mà bạn đã có câu trả lời. Tôi sẽ thử điều này, nhưng tôi chắc chắn nó sẽ không hoạt động. Tôi đã thử rất nhiều biến thể. Về cơ bản, mọi cuộc gọi '.destroyed?' *** luôn *** trả về false trong Rails 4.1 nếu được gọi từ một cuộc gọi lại 'before_destroy' hoặc' after_destroy'. –

+0

Hy vọng rằng nó hoạt động cho bạn trong Rail 4.1, bởi vì tôi đã chỉ thử nghiệm nó trong Rails 4.0, mặc dù tôi đoán rằng không nên tạo sự khác biệt. –

4

Nếu một bên của chu kỳ chỉ có một mà gọi lại, bạn có thể thay thế một trong dependent: :destroy với dependent: :delete

class User < ActiveRecord::Base 
    # delete prevents Staff's :destroy callback from happening 
    has_one: :staff, dependent: :delete 
    has_many :other_things, dependent: :destroy 
end 

class Staff < ActiveRecord::Base 
    # use :destroy here so that other_things are properly removed 
    belongs_to :user, dependent: :destroy 
end 

các Làm việc lớn đối với tôi, miễn là một bên không cần khác callbacks để bắn.

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