¿Cómo valido una fecha en los Rails?

Quiero validar una fecha en mi modelo en Ruby on Rails; sin embargo, los valores de día, mes y año ya se han convertido en una fecha incorrecta para cuando llegan a mi modelo.

Por ejemplo, si ingreso el 31 de febrero de 2009 en mi opinión, cuando uso Model.new(params[:model]) en mi controlador, lo convierte en “3 de marzo de 2009”, que luego mi modelo ve como una fecha válida. cuál es, pero es incorrecto

Me gustaría poder hacer esta validación en mi modelo. ¿Hay alguna manera que yo pueda, o estoy yendo sobre esto completamente equivocado?

Encontré esta ” Validación de fecha ” que discute el problema pero nunca se resolvió.

Supongo que estás usando el helper date_select para generar las tags para la fecha. Otra forma de hacerlo es utilizar select form helper para los campos de día, mes y año. Me gusta esto (el ejemplo que utilicé es el campo de fecha 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 %> 

Y en el modelo, valida la fecha:

 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 

Si está buscando una solución de complemento, debería consultar el complemento validates_timeliness . Funciona así (desde la página de 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 

La lista de métodos de validación disponibles es la siguiente:

 validates_date - validate value as date validates_time - validate value as time only ie '12:20pm' validates_datetime - validate value as a full date and time validates - use the :timeliness key and set the type in the hash. 

Usando la gem crónica:

 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 

Si quieres compatibilidad con Rails 3 o Ruby 1.9, prueba con la gem date_validator .

Active Record le _before_type_cast atributos _before_type_cast que contienen los datos de atributo sin procesar antes del encasillado. Esto puede ser útil para devolver mensajes de error con valores previos a la transmisión o simplemente hacer validaciones que no son posibles después de la conversión.

Me abstendría de la sugerencia de Daniel Von Fange de anular el acceso, ya que al hacer la validación en un acceso, el contrato de acceso cambia ligeramente. Active Record tiene una función explícitamente para esta situación. Úselo.

Como necesita manejar la cadena de fecha antes de que se convierta a una fecha en su modelo, anularía el acceso para ese campo

Digamos que su campo de fecha es published_date . Agregue esto a su objeto modelo:

 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 

Aquí hay una respuesta no crónica …

 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 

Un poco tarde aquí, pero gracias a ” ¿Cómo valido una fecha en los Rails? ” Logré escribir este validador, la esperanza es útil para alguien:

Dentro de tu 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 

Puede validar la fecha y la hora de esa manera (en un método en algún lugar de su controlador con acceso a sus parámetros si está utilizando selecciones personalizadas) …

 # 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 

¿Has probado el complemento validates_date_time ?