2009-09-03 10 views

Répondre

40

Il n'y a pas intégré dans ActiveRecord validateur pour DateTimes, mais vous pouvez facilement ajouter ce genre de capacité à un modèle ActiveRecord, sans l'aide d'un plug-in, avec quelque chose comme ceci:

class Thing < ActiveRecord::Base 
    validate :happened_at_is_valid_datetime 

    def happened_at_is_valid_datetime 
    errors.add(:happened_at, 'must be a valid datetime') if ((DateTime.parse(happened_at) rescue ArgumentError) == ArgumentError) 
    end 
end 
+0

Parfait, merci Gabe. – Daniel

+0

Je suis content que cela a aidé. Ce n'est pas le code le plus glorieux, mais ça fonctionne. –

+0

Merci, c'est génial. Essayé 'validates_timeliness' mais a eu des problèmes en utilisant des getters et setters. Cela a fonctionné parfaitement. –

-2

Il est tout à fait nécessaire de valider Rendez-vous. Avec les helpers de formulaire Rails par défaut, vous pouvez sélectionner des dates comme le 31 septembre.

+0

La validation de l'entrée de l'utilisateur à travers les formulaires est un bon début, mais le contexte de la question suggère que le PO posait des questions sur les validations du modèle de Rails. –

12

réponse de Gabe ne fonctionnait pas pour moi, voici donc ce que je faisais pour valider mes dates:

class MyModel < ActiveRecord::Base 
    validate :mydate_is_date? 

    private 

    def mydate_is_date? 
    if !mydate.is_a?(Date) 
     errors.add(:mydate, 'must be a valid date') 
    end 
    end 
end 

Je cherchais juste de valider que la date est en fait une date, et non une chaîne, caractère, int, float, etc ...

validation de ce jour plus complexe se trouve ici: https://github.com/codegram/date_validator

+1

La gemme est la solution la plus facile, m'a pris trois minutes pour mettre en œuvre. Ça ne vaut pas le coup d'écrire du code. –

+2

@MichaelSchmitz - Il vaut la peine d'écrire du code parce que le code est explicite - les nouvelles personnes regardant le code pourraient ne pas connaître l'existence de ces gemmes et cela ajoute une surcharge supplémentaire pour ce qui est une tâche simple. – Toby

+0

@Toby - merci pour le pointeur, vous avez raison à ce sujet. Je suis le seul développeur pour l'instant, je suppose que j'étais juste heureux que ça a marché. –

1

Vous pouvez créer un validateur datetime personnalisé par vous-même

1) créer un dossier nommé validateurs dans le répertoire d'applications à l'intérieur

2) créer un datetime_validator.rb de fichier. avec le contenu suivant dans l'application/validateurs répertoire

class DatetimeValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    if ((DateTime.parse(value) rescue ArgumentError) == ArgumentError) 
     record.errors[attribute] << (options[:message] || "must be a valid datetime") 
    end 
    end 
end 

3) Appliquer cette validation sur le modèle

class YourModel < ActiveRecord::Base 
    validates :happend_at, datetime: true 
end 

4) Ajouter la ligne ci-dessous dans application.rb

config.autoload_paths += %W["#{config.root}/app/validators/"] 

5) Restart application de votre rail

Remarque: La méthode ci-dessus testée dans les rails 4

6

Les versions récentes de Rails prendront en charge les valeurs type cast avant la validation. Les valeurs non valides seront donc transmises aux valideurs personnalisés sous la forme nil. Je fais quelque chose comme ceci:

# app/validators/date_time_validator.rb 
class DateTimeValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    if record.public_send("#{attribute}_before_type_cast").present? && value.blank? 
     record.errors.add(attribute, :invalid) 
    end 
    end 
end 
# app/models/something.rb 
class Something < ActiveRecord::Base 
    validates :sold_at, date_time: true 
end 
# spec/models/something_spec.rb (using factory_girl and RSpec) 
describe Something do 
    subject { build(:something) } 

    it 'should validate that :sold_at is datetimey' do 
    is_expected.not_to allow_value(0, '0', 'lorem').for(:sold_at).with_message(:invalid) 
    is_expected.to allow_value(Time.current.iso8601).for(:sold_at) 
    end 
end 
Questions connexes