Rails chronic pearl not confirmed as expected

I am trying to enter the date '03 / 20/1985 'into the birthday text box and paste it into the database field with the column type' date '.

When I enter 10/20/1985 , I get the error message "Birthday is invalid", but when I enter 20/10/1985 , it works fine.

Of all the documentation I read, chronic should parse "10/20/1985" as mm / dd / yyyy, but it seems like it parse it as dd / mm / yyyy.

How can I do this date parsing like mm / dd / yyyy?

/models/user.rb

 class User < ActiveRecord::Base # Include default devise modules. Others available are: # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login] # Virtual attribute for authenticating by either username or email # This is in addition to a real persisted field like 'username' attr_accessor :login # Setup accessible (or protected) attributes for your model attr_accessible :email, :password, :password_confirmation, :remember_me, :username, :login, :first_name, :last_name, :home_phone, :cell_phone, :work_phone, :birthday, :home_address, :work_address, :position, :company validate :birthday_is_date validate :position, :presence => true require 'chronic' # validate the birthday format def birthday_is_date errors.add(:birthday, "is invalid") unless Chronic.parse(birthday) end # validates email or username when logging in def self.find_first_by_auth_conditions(warden_conditions) conditions = warden_conditions.dup if login = conditions.delete(:login) where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first else where(conditions).first end end end 
+4
source share
2 answers

If the value is stored as a date in the database, Rails will force the value from the string to the Ruby date when assigned. I think it probably uses the built-in Date.parse ( docs ) method:

 Date.parse "2012-10-20" # => #<Date 2012-10-20 ...> Date.parse "20-10-2012" # => #<Date 2012-10-20 ...> Date.parse "10-20-2012" # => ArgumentError: invalid date 

In this case, you want to avoid coercion and access the raw string for analysis using Chronic. This is an ideal use case for virtual attributes . There are several ways to do this, something like this should start.

 class User < ActiveRecord::Base validate :birthday_is_date # an explicit implementation def birthday_string if @birthday_string @birthday_string elsif birthday.present? birthday.strftime("%d-%m-%Y") else "" end end # a shorter implementation def birthday_string @birthday_string || birthday.try(:strftime, "%d-%m-%Y") end def birthday_string=(value) @birthday_string = value self.birthday = parse_birthday end private def birthday_is_date errors.add(:birthday_string, "is invalid") unless parse_birthday end def parse_birthday Chronic.parse(birthday_string) end end 

And then use birthday_string in your forms, not birthday .

+3
source

Both work for me, maybe you need an update.

also:

 Chronic.parse '2/10/1985' #=> 1985-02-10 12:00:00 +0800 Chronic.parse '2/10/1985', :endian_precedence => :little #=> 1985-10-02 12:00:00 +0800 
+1
source

Source: https://habr.com/ru/post/1444984/


All Articles