سؤال

عند تدمير مورد مريح، أريد ضمان بعض الأشياء قبل السماح باستمرار عملية التدمير؟في الأساس، أريد القدرة على إيقاف عملية التدمير إذا لاحظت أن القيام بذلك سيؤدي إلى وضع قاعدة البيانات في حالة غير صالحة؟لا توجد عمليات رد اتصال للتحقق من صحة عملية التدمير، فكيف يمكن "التحقق" من صحة ما إذا كان ينبغي قبول عملية التدمير؟

هل كانت مفيدة؟

المحلول

يمكنك رفع استثناء ثم التقاطه.يقوم ريلز بتغليف عمليات الحذف في المعاملة، مما يساعد في الأمور.

على سبيل المثال:

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 لإضافته:

https://github.com/rails/rails/issues/32376

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top