2015-08-17 4 views
3

Мое приложение имеет пользовательский ввод два раза, и я вычисляю количество времени между ними как удобство для пользователя. Таким образом, пользователь вводит 1:00 AM в качестве времени начала и 2:00 AM в качестве времени остановки, он выдаст «1 час». У меня есть вспомогательный метод, который делает это, используя драгоценный камень для тяжелого подъема. Время хранится как тип данных времени в базе данных, чтобы это работало.Время проверки в рельсах

Это все работает нормально, и теперь я хочу подтвердить, что время входа пользователя действительно, но также НЕ требуется. Поэтому, если пользователь не вводит ничего для тех времен, запись по-прежнему сохраняется, но если пользователь входит, скажем, «asdfasdf», я хочу, чтобы проверки активировались и говорили, что это недействительное время, а не просто молча не хранить время ,

Я создал свои собственные пользовательские проверки времени, как так:

class TimeValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    Time.parse(value.to_s) 
    rescue ArgumentError 
    record.errors[attribute] << (options[:message] || "is not a valid time") 
    end 
end 

Тогда в моей модели, я делаю:

validates :start_time, time: true 
validates :stop_time, time: true 

Это то, что я хочу, насколько убедившись, что время может быть правильно разобран, на нем работает очень хорошо. Пользователь может ввести 14:00, 3:00 PM и т. Д., И Rails может его проанализировать. Если они вводят «asdfasdf» или любое значение, которое не может быть проанализировано как действительное время, пользователь уведомляется посредством ошибки проверки формы, и запись не сохраняется.

Но поскольку этот код стоит, он также вызывает ошибку проверки, если значение остается пустым.

Итак, я хочу, чтобы он прошел проверку с нулевым значением, но сбой, если есть какое-то значение, которое невозможно разобрать.

Я пробовал:

validates :start_time, time: true, allow_blank: true 

, но затем "asdfasdf" пройдет. Я также пробовал

Time.parse(value.to_s) unless value.nil? 

но опять же, что разрушает все это и позволяет пропустить недействительные даты.

Любые идеи?

+0

1) Что происходит, когда вы используете allow_nil вместо пустой? 2) Поскольку у вас есть класс валидатора, возможно, используйте: validates_with (см. Doc http://edgeguides.rubyonrails.org/active_record_validations.html#format). Я посмотрел на него сам на днях, но не использовал его. Поэтому я не уверен, что это помогает. – Mauddev

ответ

1

Ты почти там, вам просто нужно explitly сказать, что ноль действует

class TimeValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    return true unless value #nil value is valid 
    Time.parse(value.to_s) 
    rescue ArgumentError 
    record.errors[attribute] << (options[:message] || "is not a valid time") 
    end 
end 
+0

Это не работает. Значение «asdf» не приведет к ошибке проверки в приведенном выше коде. Я не совсем понимаю, почему. – gregblass

+0

Я подтвердил, что значение действительно отправляется как «asdf», но затем внутри метода validate_each значение уже было изменено на nil этой точкой где-то в стеке Rails ... – gregblass

0

Если вы хотите использовать самоцветы, вы можете использовать это.

Это подтверждает времени и даты. См. Здесь несколько примеров:

validates_datetime :occurred_at 

validates_date :date_of_birth, :before => lambda { 18.years.ago }, 
           :before_message => "must be at least 18 years old" 

validates_datetime :finish_time, :after => :start_time # Method symbol 

validates_date :booked_at, :on => :create, :on_or_after => :today # See Restriction Shorthand. 

validates_time :booked_at, :between => ['9:00am', '5:00pm'] # On or after 9:00AM and on or before 5:00PM 
validates_time :booked_at, :between => '9:00am'..'5:00pm' # The same as previous example 
validates_time :booked_at, :between => '9:00am'...'5:00pm' # On or after 9:00AM and strictly before 5:00PM 

validates_time :breakfast_time, :on_or_after => '6:00am', 
           :on_or_after_message => 'must be after opening time', 
           :before => :lunchtime, 
           :before_message => 'must be before lunch time' 
2

Должен признать, что я не специалист по Rails/Ruby.

У меня была такая же проблема сегодня, и я думаю, что понял. Проблема заключается в том, что Rails выполняет литье типов. Если вы введете недопустимый параметр (например, starttime = "asdf"), будет создан объект Dummy Time. Когда вы проверяете это, кажется, что все прошло хорошо, хотя, очевидно, это не так.Вы можете получить доступ к «реальному» значению параметра с помощью :starttime_before_type_cast.

я настроил код Юла соответствующим образом:

class TimeValidator < ActiveModel::EachValidator 

    def validate_each(record, attribute, value) 
    return true unless value 
    begin 
     Time.parse(value.to_s) 
    rescue ArgumentError 
     y = attribute.to_s 
     y.slice! "_before_type_cast" 
     record.errors[y] << (options[:message] || "invalid time format entered") 
    end 
    end 

end 

проверки достоверности в модели должно выглядеть примерно так:

validates :starttime, presence: true 
validates :starttime_before_type_cast, time: true 

Единственная загвоздка с этим подходом является то, что поле в форме будет содержать время 00:00, а не отклоненное значение после проверки. То есть Пользователь не увидит, что он ввел, и что приводит к сообщению об ошибке.

An article about Rails Type Casting

Смежные вопросы