Khi hủy tài nguyên an toàn, tôi muốn đảm bảo một vài điều trước khi tôi cho phép hoạt động phá hủy tiếp tục? Về cơ bản, tôi muốn có khả năng ngừng hoạt động phá hủy nếu tôi lưu ý rằng làm như vậy sẽ đặt cơ sở dữ liệu ở trạng thái không hợp lệ? Không có callbacks xác nhận về một hoạt động phá hủy, do đó, làm thế nào một "xác nhận" cho dù một hoạt động phá hủy nên được chấp nhận?Làm cách nào để 'xác thực' khi hủy đường ray
Trả lời
Bạn có thể tăng ngoại lệ mà bạn bắt được. Rails kết thúc tốt đẹp xóa trong một giao dịch, giúp các vấn đề.
Ví dụ:
class Booking < ActiveRecord::Base
has_many :booking_payments
....
def destroy
raise "Cannot delete booking with payments" unless booking_payments.count == 0
# ... ok, go ahead and destroy
super
end
end
Hoặc bạn có thể sử dụng callback before_destroy. Cuộc gọi lại này thường được sử dụng để hủy các bản ghi phụ thuộc, nhưng bạn có thể ném một ngoại lệ hoặc thêm một lỗi thay vào đó.
def before_destroy
return true if booking_payments.count == 0
errors.add :base, "Cannot delete booking with payments"
# or errors.add_to_base in Rails 2
false
# Rails 5
throw(:abort)
end
myBooking.destroy
bây giờ sẽ trả về false, và myBooking.errors
sẽ được áp dụng vào trở lại.
Um, có gì sai với chỉ kiểm tra các hiệp hội booking_payments cần được xác định trên mô hình mà thay vì gọi BookingPayment .count, dẫn đến mã xấu? –
Tôi đã chỉnh sửa trả lời của mình cho phù hợp. Xin lỗi, tôi đã kéo cái này ra khỏi một số mã cũ ... –
Lưu ý rằng bây giờ nó nói "... ok, tiếp tục và tiêu diệt", bạn cần đặt "siêu", vì vậy phương pháp phá hủy ban đầu thực sự được gọi. –
Bạn cũng có thể sử dụng gọi lại before_destroy để tăng ngoại lệ.
Các liên kết ActiveRecord has_many và has_one cho phép tùy chọn phụ thuộc để đảm bảo các hàng trong bảng có liên quan bị xóa khi xóa, nhưng điều này thường giữ cho cơ sở dữ liệu của bạn sạch hơn là ngăn không hợp lệ.
+1 cho "\ _" không nhận ra rằng đó là một tùy chọn trên SO – ahsteele
Một cách khác để chăm sóc dấu gạch dưới, nếu chúng là một phần của tên hàm hoặc tương tự, là quấn chúng vào các dấu gạch chéo ngược. Điều đó sẽ hiển thị sau đó dưới dạng mã, 'like_so'. –
Bạn có thể quấn phá hủy hành động trong một "nếu" tuyên bố trong bộ điều khiển:
def destroy # in controller context
if (model.valid_destroy?)
model.destroy # if in model context, use `super`
end
end
đâu valid_destroy? là một phương thức trên lớp mô hình của bạn trả về true nếu các điều kiện hủy phá bản ghi được đáp ứng.
Có phương pháp như vậy cũng sẽ cho phép bạn ngăn hiển thị tùy chọn xóa cho người dùng - điều này sẽ cải thiện trải nghiệm người dùng khi người dùng không thể thực hiện thao tác bất hợp pháp.
Vòng lặp vô hạn, bất kỳ ai? – jenjenut233
bắt tốt, nhưng tôi đã giả định phương pháp này là trong bộ điều khiển, trì hoãn mô hình. Nếu nó là trong mô hình chắc chắn sẽ gây ra vấn đề –
hehe, xin lỗi bout rằng ... Tôi thấy những gì bạn có nghĩa là, tôi chỉ thấy "phương pháp trên lớp mô hình của bạn" và nhanh chóng nghĩ "uh oh", nhưng bạn đúng - tiêu diệt trên bộ điều khiển, điều đó sẽ hoạt động tốt. :) – jenjenut233
chỉ là một lưu ý:
Đối với đường ray 3
class Booking < ActiveRecord::Base
before_destroy :booking_with_payments?
private
def booking_with_payments?
errors.add(:base, "Cannot delete booking with payments") unless booking_payments.count == 0
errors.blank? #return false, to not destroy the element, otherwise, it will delete.
end
Một vấn đề với cách tiếp cận này là callback before_destroy có vẻ được gọi là * sau khi * tất cả các booking_payments đã bị phá hủy. – sunkencity
Vé liên quan: https://github.com/rails/rails/issues/3458 @sunkencity bạn có thể khai báo before_destroy trước khi tuyên bố kết hợp để tạm thời tránh điều này. – lulalala
tôi đã kết thúc sử dụng mã từ vào đây để tạo một ghi đè can_destroy trên activerecord: https://gist.github.com/andhapp/1761098
class ActiveRecord::Base
def can_destroy?
self.class.reflect_on_all_associations.all? do |assoc|
assoc.options[:dependent] != :restrict || (assoc.macro == :has_one && self.send(assoc.name).nil?) || (assoc.macro == :has_many && self.send(assoc.name).empty?)
end
end
end
này đã cho biết thêm lợi ích của việc làm cho nó tầm thường để ẩn/hiển thị nút xóa trên ui
Tôi có các lớp hoặc các mô hình
class Enterprise < AR::Base
has_many :products
before_destroy :enterprise_with_products?
private
def empresas_with_portafolios?
self.portafolios.empty?
end
end
class Product < AR::Base
belongs_to :enterprises
end
Bây giờ khi bạn xóa một doanh nghiệp quá trình này xác nhận nếu có những sản phẩm liên quan đến doanh nghiệp Lưu ý: Bạn phải viết này trong top của lớp để xác nhận nó Đầu tiên.
Đó là những gì tôi đã làm với Rails 5:
before_destroy do
cannot_delete_with_qrcodes
throw(:abort) if errors.present?
end
def cannot_delete_with_qrcodes
errors.add(:base, 'Cannot delete shop with qrcodes') if qrcodes.any?
end
Đây là một bài viết hay giải thích hành vi này trong Rails 5: http://blog.bigbinary.com/2016/02/13/rails-5-does-not-halt-callback-chain-when-false-is- return.html –
Sử dụng ActiveRecord xác nhận bối cảnh trong Rails 5.
class ApplicationRecord < ActiveRecord::Base
before_destroy do
throw :abort if invalid?(:destroy)
end
end
class Ticket < ApplicationRecord
validate :validate_expires_on, on: :destroy
def validate_expires_on
errors.add :expires_on if expires_on > Time.now
end
end
liên quan: http://stackoverflow.com/questions/5520320/validate-before-destroy –