2011-04-02 98 views
46

我有三个班级:学校,帐户和管理员。破坏前验证

学校

的has_many:administatorships

的has_many:管理员:通过=>:遗产管理人

帐户

的has_many:遗产管理人

管理人的职位

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 

现在,我想发生的事情是,当我打电话destroy对管理人的职位的实例,为它的错误添加到模型,并防止模型的破坏。我已经删除了except语句以查看是否阻止了添加错误,但事实并非如此。似乎在模型上有错误并不能防止发生破坏。

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

+0

可能重复[我如何验证'在摧毁在轨道](http:// stackoverflow。问题/ 123078 /我如何做 - 我在轨道上被破坏) – 2014-06-26 18:50:28

+0

不应该是'> 1'吗?在删除发生之前,是不是执行了这个查询? – panzi 2016-02-10 18:09:11

+0

@panzi这是它的统计任何管理员没有当前管理员的帐户ID – tanman 2016-02-11 18:22:44

回答

64

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

+2

对于你希望对象在销毁之前处于有效状态的一般情况,你可以这样做:'before_destroy:valid?' – Pathogen 2014-03-05 21:59:08

+1

如果立即返回,似乎会在Rails 4.1中引发'LocalJumpError:unexpected return',请参见https:// github.com/rails/rails/issues/12981'#Fix 1' – 2015-02-05 09:35:30

14

从验证方法中返回false将防止记录被破坏。

实施例:

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 

附注:我在和不被显示该错误信息的麻烦。验证会起作用,对象不会被删除,但是没有消息让我知道发生了什么。原因是控制器重定向到索引视图而不是呈现删除视图(例如,如果在创建新用户时出现错误,它将呈现:action =>'new'。在这种情况下,没有删除视图)。发生这种情况时,设置了错误消息的实例变量(在errors.add(:base,“message”)中)实际上正在重置,这会破坏进程中的错误。

+2

有没有什么办法可以解决您在备注中提到的问题? – 2012-01-29 10:12:25

+5

为了解决在**侧面说明**长大的问题,添加类似以下的'redirect_to'行的相关负责人的破坏作用:'format.html {redirect_to的products_url,:通知=>“的发生错误!#{{products.errors [:base] .to_s}“}'。然后,只要您在应用中的某个地方显示Flash消息(例如application.html.erb),它就会出现。请参阅[本指南](http://guides.rubyonrails.org/action_controller_overview.html#the-flash)和[此问题](http://stackoverflow.com/q/9390778/664833)。 – user664833 2012-02-23 22:19:35

1

我结束了使用代码从这里到创建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 

这使得它琐碎隐藏的额外的好处/显示在用户界面上删除按钮

4

这是一个Rails 5答案,如果你返回false,它会给出一个弃用警告:“在Active Record和Active Model回调中返回false不会隐式地停止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

在Rails 5.1.4中,我甚至没有看到弃用警告。 – 2017-12-20 19:26:40