2012-10-23 9 views
15

Mam model z atrybutem datetime. Próbuję sprawdzić poprawność przychodzącego JSON, który zaktualizuje model. Ale ActiveRecord wydaje się ustawiać wartość atrybutu na zero, jeśli jest to niepoprawna data/godzina. Nie mogę odpowiedzieć odpowiednim błędem, ponieważ atrybut może być zerowy. Co ja robię źle?Rails niepoprawna data/godzina na modelu wyniki w zerowej

Kod:

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 

konsoli:

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 

miarę ActiveRecord obawia się, ustawiając atrybut datetime do 'bad_value' jest równoważne ustawieniu go do zera, więc nie mogę sprawdź poprawność, ponieważ my_date nie jest wymagane. Wydaje mi się, że to błąd. Jakie jest najlepsze obejście tego problemu?

Dzięki!

+0

Czy wszystko działa, jeśli usuniesz ': allow_nil => true'? –

+0

Tak, wydaje się, że działa (chociaż z jakiegoś powodu otrzymuję podwójne komunikaty o błędach przy pierwszym uruchomieniu .valid?). Dostaję oczekiwany "musi być datą". –

Odpowiedz

8

Jeden obejście byłoby przesunąć allow_nil udział w walidacji date_time:

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: Myślę, że to problem z rzutowania - spróbuj tego (dostosowany od kodu dla 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, patrz edycja. –

+0

Nie, to nie działa. Wartość jest zawsze zerowa, chyba że jest to poprawna data-godzina, więc Foo.new (: my_date => "wrong"). Valid? # => true –

+0

Zmieniony kod z elementami 'before_type_cast' nie działa? –

Powiązane problemy