Я хочу проверить дату в моей модели в Ruby on Rails, однако значения дня, месяца и года уже преобразованы в неправильную дату к тому времени, когда они достигнут моей модели.
Например, если я ввожу 31 февраля 2009 года в моем представлении, когда я использую Model.new(params[:model])
в своем контроллере, он преобразует его в «3 марта 2009 года», который моя модель затем видит как действительную дату, что и есть, но это неверно.
Я хотел бы иметь возможность провести эту проверку в моей модели. Есть ли способ, которым я могу это сделать, или я ошибаюсь?
Я нашел эту « проверку даты », в которой обсуждается проблема, но она так и не была решена.
ruby-on-rails
ruby
validation
date
Мегамуг
источник
источник
Ответы:
Я предполагаю, что вы используете
date_select
помощника для создания тегов для даты. Другой способ сделать это - использовать помощник формы выбора для полей дня, месяца, года. Вот так (я использовал поле даты created_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.
источник
Использование хронического драгоценного камня:
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
источник
Chronic.parse(from_date_before_type_cast)
для ввода строкового значения. В противном случае Rails привел бы строкуto_date
к типу, поскольку поле былоdatetime
полем.Если вам нужна совместимость с Rails 3 или Ruby 1.9, попробуйте гем date_validator .
источник
Active Record предоставляет вам
_before_type_cast
атрибуты, которые содержат необработанные данные атрибутов перед приведением типов. Это может быть полезно для возврата сообщений об ошибках со значениями до приведения типов или просто для выполнения проверок, которые невозможны после приведения типов.Я бы уклонился от предложения Даниэля фон Фанге переопределить метод доступа, потому что выполнение проверки в методе доступа немного изменяет контракт с ним. Active Record имеет функцию, специально предназначенную для этой ситуации. Используй это.
источник
Немного поздно, но благодаря « Как мне проверить дату в рельсах? » Мне удалось написать этот валидатор, надеюсь, это кому-то пригодится:
Внутри вашего
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
источник
Поскольку вам нужно обработать строку даты, прежде чем она будет преобразована в дату в вашей модели, я бы переопределил метод доступа для этого поля
Допустим, у вас есть поле даты
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
источник
Вот не хронический ответ ..
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
источник
"1/1/2013".is_a?(Date)
- Дата вводится пользователем, поэтому она передается в виде строки. Придется сначала разобрать это как свидание?Date.parse("1/1/2013").is_a?(Date)
, но вы могли видеть, что если он вообще не разбирается, вероятно, это также не дата.Вы можете проверить дату и время таким образом (в методе где-то в вашем контроллере с доступом к вашим параметрам, если вы используете пользовательские выборки) ...
# 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
источник
Вы пробовали
validates_date_time
плагин?источник