2010-11-19 4 views
6

У меня есть приложение Rails 3 (с использованием Mongodb и Mongoid, если это имеет значение), и в одной из моих моделей у меня есть поле, определенное как тип Date.Дата проверки в Rails 3

class Participant 
    include Mongoid::Document 

    field :birth_date, :type => Date 
end 

Мой контроллер использует find_or_initialize_by особенность Монго:

class ParticipantController 

    def create 
    @participant = Participant.find_or_initialize_by(params[:participant]) 
    if @participant.save 
     redirect_to participants_path 
    else 
     render :new 
    end 
    end 
end 

Все это сводится к: как делать проверку даты в ActiveModel с Mongoid и Rails 3?

Я хочу убедиться, что ввод «бла», как в текстовом поле, не генерирует исключение при назначении в поле .birth_date моей модели. Он должен обеспечить хорошее сообщение об ошибке проверки без использования контроллера для проверки.

Вот основные требования:

  • мнение должно быть одно текстовое поле. Больше ничего. Это пользователь требование о том, что мы не можем изменить

  • Проверка должна быть сделана в модели, а не в контроллере или
    вид (JavaScript или любой другой)

  • Нет формат регулярных выражений валидаций (они не работают право/поддержка локали и т.д.)

проблема заключается в том, что значение из текстового поля присваивается .birth_date перед тем validates_format_of и validates_presence_of выполняются. поэтому ...

как перехватить назначение значения, чтобы я мог проверить его до его назначения? возможно ли это сделать в модели, используя ActiveModel? или это требует от меня ввода кода в контроллер для этого?

+0

Почему вы не проводите проверку даты в своем контроллере? Определите метод в вашей модели, который вызывает «ArgumentError», если дата недействительна, а затем ваш контроллер использует этот метод, например «рейз». Вы не указали допустимую дату «если только @ member.date_is_valid» – Alex

+0

. Также вы могли бы предоставить немного больше информации о том, что вы подразумеваете под «действительной» датой? Действительная строка даты и времени RFC? Дата может быть отформатирована по-разному. Любая дополнительная информация была бы полезной – Alex

ответ

8

Этот небольшой блок кода может сделать трюк

retVal = "it is a date" 
begin 
    y = Date.parse("rodman was here") 
rescue 
    retVal = "nope not a date" 
end 

puts retVal 
+2

столько, сколько мне не нравится, вот что мы в итоге использовали. в один из этих дней я собираюсь написать плагин для рельсов, чтобы обработать это более элегантно .... на днях ... когда у меня есть свободное время ...: P –

+2

Я рекомендую камень validates_timeliness. –

2

Я только что нашел это, хотя я еще не играл с ним:

http://blog.codegram.com/2011/2/date-validation-with-rails-3

Github репозиторий находится в https://github.com/codegram/date_validator

Кабинет из блога:

«Вы можете использовать его как в Rails 3 модели или в любом пользовательском классе (потребовав ActiveModel), в очень легкой манере

Они также дают пример того, что делает его, кажется, как она должна работать вы - это сделано в модели, а не в контроллере.

validates expiration_date, 
    :date => { :after => Time.now, :before => Time.now + 1.year } 
+3

Будьте очень осторожны в отношении временных меток в контексте класса. В Rails-производстве эти даты будут временем, определяемым классом, который начинается при запуске сервера приложений. Как указано в описании date_validator, передайте дату в 'Proc'. –

2

Необходимо использовать фильтр before_validation, например. в модели

class Participant 
    include Mongoid::Document 
    before_validation :make_a_date 
    field :birth_date, :type => Date 

    private 
    def make_a_date 
    #do all sorts of manipulation of the date here 
    end 
end 

другой альтернативы можно было бы создать свой собственный метод проверки? Но я не думаю, вот что вы хотите ...

0

Альтернатива заключается в создании класса валидации, который расширяет ActiveModel :: EachValidator, например:

class TimeValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    if value && !value.kind_of?(Time) 
     record.errors[attribute] << (options[:message] || "don't recognise time") 
    end 
    end 
end 

В приведенном выше примере я муфты это с методом setter на модели, которая обрабатывает синтаксический анализ, если строка передана. Я хотел поддерживать нечеткое согласование по дате, поэтому я использую Chronic.

require 'chronic' 

def starts_at=(value) 
    if value.kind_of?(String) && parsed_time = Chronic.parse(value) 
    @starts_at = parsed_time.utc 
    else 
    @starts_at = value 
    end 
end 

и это настроить валидатор на модели

validates :starts_at, :time => true 

который хорош и условна.

+0

Но если дата из пользовательского ввода 'kind_of? (Time)' всегда будет возвращать значение false. '" 12/12/1912 ".kind_of? (Дата) => false'. Так как это будет работать? – Mohamad

4

validates_timeliness драгоценный камень довольно сладкий. Вы можете просто сделать что-то вроде этого:

class Participant < ActiveRecord::Base 
    validates_date :birth_date 
end 
Смежные вопросы