كيف يمكنني "التحقق" من التدمير في القضبان
-
02-07-2019 - |
سؤال
عند تدمير مورد مريح، أريد ضمان بعض الأشياء قبل السماح باستمرار عملية التدمير؟في الأساس، أريد القدرة على إيقاف عملية التدمير إذا لاحظت أن القيام بذلك سيؤدي إلى وضع قاعدة البيانات في حالة غير صالحة؟لا توجد عمليات رد اتصال للتحقق من صحة عملية التدمير، فكيف يمكن "التحقق" من صحة ما إذا كان ينبغي قبول عملية التدمير؟
المحلول
يمكنك رفع استثناء ثم التقاطه.يقوم ريلز بتغليف عمليات الحذف في المعاملة، مما يساعد في الأمور.
على سبيل المثال:
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
وبدلاً من ذلك، يمكنك استخدام رد الاتصال before_destroy.يُستخدم رد الاتصال هذا عادةً لتدمير السجلات التابعة، ولكن يمكنك طرح استثناء أو إضافة خطأ بدلاً من ذلك.
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
سيعود الآن كاذبة، و myBooking.errors
سيتم ملؤها عند العودة.
نصائح أخرى
مجرد ملاحظة:
للقضبان 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
وهذا ما فعلته مع 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
تسمح اقترانات ActiveRecord has_many و has_one بخيار تابع يضمن حذف صفوف الجدول ذات الصلة عند الحذف، ولكن هذا عادةً للحفاظ على قاعدة بياناتك نظيفة بدلاً من منعها من أن تكون غير صالحة.
يمكنك تغليف إجراء التدمير في عبارة "if" في وحدة التحكم:
def destroy # in controller context
if (model.valid_destroy?)
model.destroy # if in model context, use `super`
end
end
أين صالح_تدمير؟ هي طريقة موجودة في فئة النموذج الخاص بك والتي تُرجع صحيحًا إذا تم استيفاء شروط تدمير السجل.
سيسمح لك وجود طريقة كهذه أيضًا بمنع عرض خيار الحذف للمستخدم - مما سيؤدي إلى تحسين تجربة المستخدم حيث لن يتمكن المستخدم من تنفيذ عملية غير قانونية.
انتهى بي الأمر باستخدام الكود من هنا لإنشاء تجاوز can_destroy على 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
وهذا له فائدة إضافية تتمثل في جعل إخفاء/إظهار زر الحذف على واجهة المستخدم أمراً تافهاً
يمكنك أيضًا استخدام رد الاتصال before_destroy لرفع الاستثناء.
لدي هذه الفئات أو النماذج
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
الآن عندما تقوم بحذف مؤسسة ، فإن هذه العملية تتحقق من صحة إذا كانت هناك منتجات مرتبطة بالمؤسسات ملاحظة:يجب عليك كتابة هذا في أعلى الفصل للتحقق من صحته أولاً.
استخدم التحقق من صحة سياق ActiveRecord في 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
كنت أتمنى أن يتم دعم هذا لذا فتحت مشكلة Rails لإضافته: