2016-06-09 70 views
0

我使用before_validation來確保我的User模型的狀態。ActiveRecord :: Base before_validation with conditional not triggered

before_validation :renter, if: 'resident? && active? && unit.present? && units.empty?' 

當我嘗試使用新記錄時,條件爲真。

user.resident? && user.active? && user.unit.present? && user.units.empty? 
=> true 

而且回調在沒有條件的情況下完美運作。

但是,使用具有條件的回調不起作用。

user = User.new(resident_attr_except_resident_type) 
user.save 
=> false 
user.errors.full_messages 
=> ["Resident type can't be blank"] 

user.renter 
=> #<User ..., resident_type: 0> # resident_type 0 because is a enum 
user.save 
=> true 

只是爲了澄清,該renter方法執行以下操作:

def renter 
    self.resident_type = :renter 
    self 
end 

def renter! 
    renter.save 
end 

這有什麼,我很想念?

我懷疑兩件事1)有條件的和2)renter的回報和我誤解before_validation如何工作。

回答

0

,你可以嘗試這個...

before_validation :renter, if: :check_renter? 

def check_renter? 
    resident? && active? && unit.present? && units.empty? 
end 
+0

上帝不!我之前在另一個項目中這樣做,這是一個完整的噩夢。不要做?將只使用一次或兩次的方法! – fbelanger

+0

@fbelanger:我同意Sourabh的看法,你應該給這個複雜的條件一個合適的名稱,並將其轉化爲一種方法。像這樣的條件很難閱讀,併爲其他開發人員瞭解,這是很難測試。你能否詳細說明爲什麼你認爲這是一個*完整的噩夢*? – spickermann

+0

我不同意。這樣做會導致龐大的模型,但是出於所有錯誤的原因。這種方法永遠不會被真正重用,並且如果你正在編寫並行測試的話,這個方法很容易測試。在我看來,它更加清潔,使每次增量檢查分開並在回調中使用組合。否則,我最終會用'building_blank?','unit_blank?','active_resident?','acitve_resident_with_unit?','active_resident_with_unit_and_without_units?'等等。對於其他一切,但是,我爲此寫了一些方法。 – fbelanger

0

IMO你的回調和你的renter方法很難閱讀和理解。我認爲將代碼轉移到自己的方法是值得的:

before_validation :determine_renter_type 

private 
def detemine_renter_type 
    if resident? && active? && unit.present? && units.empty? 
    self.renter_type = User.renter_types[:renter] 
    end 

    self # avoid aborting the save process by returning a truthy value 
end 
+0

我比其他提議的方法更好地解決了代碼清理的問題。謝謝!雖然我會補充說這個回調會因爲我的回答中的解釋而失敗。 – fbelanger

+0

你是對的,我更新了我的答案。我總是把它與自定義驗證器混合在一起,它在返回虛假值時不會中斷過程。 – spickermann