2011-04-02 99 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