2016-06-09 11 views
0

Ich verwende before_validation, um den Zustand meiner User Modell zu gewährleisten.ActiveRecord :: Base before_validation mit bedingten nicht ausgelöst

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

Die Bedingung ist wahr, wenn ich mit einem neuen Rekord versuchte.

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

Und der Rückruf funktioniert perfekt ohne die bedingte.

Die Verwendung des Rückrufs mit der Bedingung funktioniert jedoch nicht.

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 

Nur um zu klären, die renter Methode führt Folgendes aus:

def renter 
    self.resident_type = :renter 
    self 
end 

def renter! 
    renter.save 
end 

Gibt es etwas, dass ich fehle?

Ich vermute, zwei Dinge, 1) die bedingte und 2) die Rückkehr von renter und mir missverstanden, wie before_validation funktioniert.

Antwort

0

Sie dies versuchen kann ...

before_validation :renter, if: :check_renter? 

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

Gott nicht! Ich habe das schon mal in einem anderen Projekt gemacht und es war ein kompletter Albtraum. Mach nicht? Methoden, die nur ein- oder zweimal verwendet werden! – fbelanger

+0

@fbelanger: Ich stimme Sourabh zu, dass du dieser komplexen Bedingung einen richtigen Namen gibst und sie selbst in eine Methode bringst. Eine solche Bedingung ist für andere Entwickler schwer zu lesen und zu verstehen, und es ist schwieriger zu testen. Kannst du bitte näher erläutern, warum du denkst, dass es ein kompletter Albtraum war? – spickermann

+0

Ich muss dem widersprechen. Dies führt zu einem massiv fetten Modell, aber aus den falschen Gründen. Diese Methode wird niemals wirklich wiederverwendet und ist leicht testbar, wenn Sie Ihre Tests parallel schreiben. Es ist meiner Meinung nach viel sauberer, jede inkrementelle Prüfung getrennt zu halten und Kombinationen in Rückrufen zu verwenden. Ansonsten habe ich am Ende 'building_blank?', 'Unit_blank?', 'Active_resident?', 'Acitve_resident_with_unit?', 'Active_resident_with_unit_and_without_units?', Und so weiter. Für alles andere, aber das schreibe ich Methoden für. – fbelanger

0

IMO Ihr Rückruf und Ihre renter Methode sind schwer zu lesen und zu verstehen. Ich denke es lohnt sich, diesen Code in eine eigene Methode zu verschieben:

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

Ich mag diese Lösung besser, als die andere vorgeschlagene Methode zur Bereinigung des Codes. Vielen Dank! Allerdings würde ich hinzufügen, dass dieser Rückruf aufgrund der Erklärung in meiner Antwort fehlschlagen wird. – fbelanger

+0

Sie haben Recht, ich habe meine Antwort aktualisiert. Ich vermische dies immer mit einem benutzerdefinierten Validator, der den Prozess nicht unterbricht, wenn ein falscher Wert zurückgegeben wird. – spickermann

Verwandte Themen