在销毁之前进行validation

我有三个class级:学校,帐户和pipe理员。

学校

has_many:pipe理员

has_many:pipe理员,:通过=>:pipe理员

帐户

has_many:pipe理员

pipe理人的职位

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" end end 

现在,我想要发生的情况是,我在pipe理员实例上调用destroy时,会为模型添加一个错误,并防止模型被破坏。 我已经删除了except语句来查看是否阻止了错误的添加,事实并非如此。 似乎在模型上有错误并不能防止发生破坏。

所以我的问题是,有什么办法可以防止使用validation发生破坏? 我意识到我可以定义一个只有满足上述条件才会销毁的方法,但validation方法似乎是一个更优雅的解决scheme。

如果你从before_destroy方法返回false,它将防止破坏。

从validation方法返回false将防止logging被破坏。

例:

 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 

附注:我遇到了这个错误消息不显示的麻烦。 validation会起作用,对象不会被删除,但是不会有任何信息让我知道发生了什么。 原因是控制器被redirect到索引视图,而不是呈现删除视图(如果在创build新用户时出现错误,则会渲染:action =>'new'。在这种情况下,没有删除视图)。 发生这种情况时,在其上设置了错误消息的实例variables(在errors.add(:base,“message”)中)实际上正在被重置,从而破坏了进程中的错误。

这是一个Rails 5的答案,如果你返回false,它会给出一个弃用警告: “在Active Record和Active Modelcallback中返回false不会隐式地停止Rails 5.1中的callback链”

 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 

我最终使用这里的代码来创buildactiverecord上的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 

这还有一个好处,就是在UI上隐藏/显示删除button