Как проверить дату в рельсах? - PullRequest
89 голосов
/ 28 февраля 2009

Я хочу проверить дату в моей модели в Ruby on Rails, однако значения дня, месяца и года уже преобразуются в неверную дату к тому времени, когда они достигают моей модели.

Например, если я введу 31 февраля 2009 г. в моем представлении, когда я использую Model.new(params[:model]) в своем контроллере, он преобразует его в «3 марта 2009 г.», который моя модель затем считает действительной датой, и но это неверно.

Я бы хотел провести эту проверку в моей модели. Есть ли способ, которым я могу, или я делаю это совершенно неправильно?

Я нашел это " Проверка даты ", в которой обсуждается проблема, но она так и не была решена.

Ответы [ 9 ]

58 голосов
/ 28 февраля 2009

Я предполагаю, что вы используете помощник date_select для генерации тегов для даты. Другой способ сделать это - использовать помощник выбора формы для полей дня, месяца и года. Вот так (пример, который я использовал, это поле даты create_at):

<%= f.select :month, (1..12).to_a, selected: @user.created_at.month %>
<%= f.select :day, (1..31).to_a, selected: @user.created_at.day %>
<%= f.select :year, ((Time.now.year - 20)..Time.now.year).to_a, selected: @user.created_at.year %>

А в модели вы подтверждаете дату:

attr_accessor :month, :day, :year
validate :validate_created_at

private

def convert_created_at
  begin
    self.created_at = Date.civil(self.year.to_i, self.month.to_i, self.day.to_i)
  rescue ArgumentError
    false
  end
end

def validate_created_at
  errors.add("Created at date", "is invalid.") unless convert_created_at
end

Если вы ищете плагин-решение, я бы воспользовался validates_timeliness плагином Это работает так (со страницы github):

class Person < ActiveRecord::Base
  validates_date :date_of_birth, on_or_before: lambda { Date.current }
  # or
  validates :date_of_birth, timeliness: { on_or_before: lambda { Date.current }, type: :date }
end 

Список доступных методов проверки:

validates_date     - validate value as date
validates_time     - validate value as time only i.e. '12:20pm'
validates_datetime - validate value as a full date and time
validates          - use the :timeliness key and set the type in the hash.
20 голосов
/ 11 марта 2010

Использование хронического камня:

class MyModel < ActiveRecord::Base
  validate :valid_date?

  def valid_date?
    unless Chronic.parse(from_date)
      errors.add(:from_date, "is missing or invalid")
    end
  end

end
18 голосов
/ 24 августа 2010

Если вам нужна совместимость с Rails 3 или Ruby 1.9, попробуйте date_validator gem.

10 голосов
/ 09 февраля 2011

Active Record предоставляет вам _before_type_cast атрибутов, которые содержат необработанные данные атрибутов перед приведением типов. Это может быть полезно для возврата сообщений об ошибках со значениями, предшествующими типу, или просто для проверки, которая невозможна после трансляции.

Я бы уклонился от предложения Даниэля фон Фанге о переопределении метода доступа, потому что выполнение проверки в методе доступа немного меняет контракт метода доступа. Active Record имеет функцию явно для этой ситуации. Используйте это.

3 голосов
/ 28 февраля 2009

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

Допустим, ваше поле даты published_date. Добавьте это к объекту вашей модели:

def published_date=(value)
    # do sanity checking here
    # then hand it back to rails to convert and store
    self.write_attribute(:published_date, value) 
end
2 голосов
/ 30 ноября 2016

Здесь немного поздно, но благодаря " Как проверить дату в рельсах? " Мне удалось написать этот валидатор, надеюсь, кому-нибудь пригодится:

Внутри вашего model.rb

validate :date_field_must_be_a_date_or_blank

# If your field is called :date_field, use :date_field_before_type_cast
def date_field_must_be_a_date_or_blank
  date_field_before_type_cast.to_date
rescue ArgumentError
  errors.add(:birthday, :invalid)
end
1 голос
/ 03 апреля 2013

Вот нехронический ответ ..

class Pimping < ActiveRecord::Base

validate :valid_date?

def valid_date?
  if scheduled_on.present?
    unless scheduled_on.is_a?(Time)
      errors.add(:scheduled_on, "Is an invalid date.")
    end
  end
end
0 голосов
/ 29 апреля 2015

Вы можете проверить дату и время следующим образом (в методе где-нибудь на вашем контроллере с доступом к вашим параметрам, если вы используете пользовательские выборки) ...

# Set parameters
year = params[:date][:year].to_i
month = params[:date][:month].to_i
mday = params[:date][:mday].to_i
hour = params[:date][:hour].to_i
minute = params[:date][:minute].to_i

# Validate date, time and hour
valid_date    = Date.valid_date? year, month, mday
valid_hour    = (0..23).to_a.include? hour
valid_minute  = (0..59).to_a.include? minute
valid_time    = valid_hour && valid_minute

# Check if parameters are valid and generate appropriate date
if valid_date && valid_time
  second = 0
  offset = '0'
  DateTime.civil(year, month, mday, hour, minute, second, offset)
else
  # Some fallback if you want like ...
  DateTime.current.utc
end
0 голосов
/ 28 февраля 2009

Вы пробовали подключить плагин validates_date_time?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...