Program Club

레일에서 파괴시 '검증'하는 방법

proclub 2020. 10. 23. 19:40
반응형

레일에서 파괴시 '검증'하는 방법


안정된 리소스를 파괴 할 때 파괴 작업을 계속하기 전에 몇 가지 사항을 보장하고 싶습니다. 기본적으로 데이터베이스가 유효하지 않은 상태가 될 수 있음을 알면 삭제 작업을 중지 할 수있는 기능을 원합니까? 삭제 작업에는 유효성 검사 콜백이 없습니다. 그렇다면 삭제 작업을 수락해야하는지 여부를 어떻게 "확인"합니까?


그런 다음 예외를 발생시킬 수 있습니다. Rails는 트랜잭션에서 삭제를 래핑하여 문제를 해결합니다.

예를 들면 :

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이제 false 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"문에서 destroy 액션을 래핑 할 수 있습니다.

def destroy # in controller context
  if (model.valid_destroy?)
    model.destroy # if in model context, use `super`
  end
end

valid_destroy는 어디 입니까? 레코드 삭제 조건이 충족되면 true를 반환하는 모델 클래스의 메서드입니다.

이와 같은 방법을 사용하면 사용자에게 삭제 옵션이 표시되는 것을 방지 할 수 있습니다. 이는 사용자가 불법 작업을 수행 할 수 없기 때문에 사용자 경험을 향상시킬 것입니다.


여기에서 코드를 사용하여 activerecord에 can_destroy 재정의를 만들었습니다 : 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

This has the added benefit of making it trivial to hide/show a delete button on the ui


You can also use the before_destroy callback to raise an exception.


I have these classes or models

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

Now when you delete an enterprise this process validates if there are products associated with enterprises Note: You have to write this in the top of the class in order to validate it first.


Use ActiveRecord context validation in 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

I was hoping this would be supported so I opened a rails issue to get it added:

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

참고URL : https://stackoverflow.com/questions/123078/how-do-i-validate-on-destroy-in-rails

반응형