Validate Before Destroy

后端 未结 5 1082
忘掉有多难
忘掉有多难 2020-12-13 23:49

I have three classes: School, Account, and Administratorship.

School



        
相关标签:
5条回答
  • 2020-12-14 00:25

    If you return false from that before_destroy method, it will prevent the destruction.

    0 讨论(0)
  • 2020-12-14 00:26

    Returning false from your validation method will prevent the record from getting destroyed.

    Example:

    def confirm_presence_of_alternate_administratorship_in_school
      unless school.administrators.count(["administratorships.account_id != #{id}"]) > 0
        # errors.add_to_base() is deprecated in Rails 3. Instead do...
        errors.add(:base, "The school must have at least one administrator")
    
        # this will prevent the object from getting destroyed
        return false
      end
    end
    

    Side note: I was having trouble with this error message not being displayed. The validation would work and the object would not be deleted, but there would be no message letting me know what happened. The reason for this was that the controller was redirecting to the index view instead of rendering the delete view (if there is an error while creating a new user for example, it will render :action => 'new'. In this case there is no delete view). When this happened, the instance variable on which the error message was set (in errors.add(:base,"message")) is actually being reset, which destroys the error in the process.

    0 讨论(0)
  • 2020-12-14 00:26

    For Rails 5, returningfalse won't halt the callback chain. You need to use throw(:abort)

    belongs_to :account belongs_to :school

    before_destroy :confirm_presence_of_alternate_administratorship_in_school

    protected

    def confirm_presence_of_alternate_administratorship_in_school
        unless school.administrators.count(["administratorships.account_id != #{id}"]) > 0
            errors.add_to_base "The school must have at least one administrator"
            throw(:abort)
        end
    end
    
    0 讨论(0)
  • 2020-12-14 00:32

    I ended up using code from here to create a can_destroy override on 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
    

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

    0 讨论(0)
  • 2020-12-14 00:42

    This is a Rails 5 answer, if you return false it will give a deprecation warning: "Returning false in Active Record and Active Model callbacks will not implicitly halt a callback chain in Rails 5.1".

    def confirm_presence_of_alternate_administratorship_in_school
      return if school.administrators.count(["administratorships.account_id != #{id}"]) > 0
      errors[:base] << 'The school must have at least one administrator'
      throw :abort
    end
    
    0 讨论(0)
提交回复
热议问题