2012-10-23 4 views
15

Ich habe ein Modell mit einem Datetime-Attribut. Ich versuche, eingehenden JSON zu validieren, der das Modell aktualisieren würde. Aber ActiveRecord scheint den Wert des Attributs auf Null zu setzen, wenn es ein ungültiges Datum ist. Ich kann nicht mit dem entsprechenden Fehler antworten, weil das Attribut NULL sein darf. Was mache ich falsch?Schienen ungültige Datetime auf Modell Ergebnisse in Null

Code:

class DatetimeValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    value.to_datetime rescue record.errors[attribute] << (options[:message] || "must be a date.") 
    end 
end 

class Foo 
    # column :my_date, :datetime 
    validates :my_date, :allow_nil => true, :datetime => true 
end 

Console:

1.9.3p125 :001 > x = Foo.new 
=> #<Foo id: nil, my_date: nil> 
1.9.3p125 :001 > x.my_date = 'bad value' 
=> 'bad value' 
1.9.3p125 :001 > x.my_date 
=> nil 
1.9.3p125 :001 > x.valid? 
=> true 

Soweit Active betrifft, zu 'bad_value' das Datetime-Attribut Einstellung entspricht es auf Null einstellen, so kann ich nicht validiere es, da my_date nicht benötigt wird. Das scheint mir ein Fehler zu sein. Was ist die beste Problemumgehung?

Danke!

+0

Funktioniert alles, wenn Sie das ': allow_nil => true' entfernen? –

+0

Ja, es scheint zu funktionieren (obwohl ich aus irgendeinem Grund doppelte Fehlermeldungen bekomme, wenn ich zum ersten Mal .valid starte). Ich bekomme das erwartete "Muss ein Date sein." –

Antwort

8

Eine Abhilfe wäre den allow_nil Teil in die date_time Validierung zu bewegen:

class DatetimeValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    return if value.blank? 
    value.to_datetime rescue record.errors[attribute] << (options[:message] || "must be a date.") 
    end 
end 

class Foo 
    validates :my_date, :datetime => true 
end 

Edit: Ich denke, es ist ein Problem mit Schublade gesteckt - versuchen, diese (aus dem Code angepasst für validates :numericality):

def validate_each(record, attribute, value) 
    before_type_cast = "#{attribute}_before_type_cast" 

    raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast.to_sym) 
    raw_value ||= value 

    return if raw_value.blank? 
    raw_value.to_datetime rescue record.errors[attribute] << (options[:message] || "must be a date.") 
end 
+0

Ah ok, siehe Bearbeiten. –

+0

Nein, das funktioniert nicht. Der Wert ist immer Null, es sei denn, es handelt sich um eine gültige Datetime, also Foo.new (: my_date => 'wrong'). # => true –

+0

Der bearbeitete Code mit 'before_type_cast' funktioniert nicht? –