Skip to content

Instantly share code, notes, and snippets.

@snreid
Last active August 29, 2015 14:08
Show Gist options
  • Save snreid/66413ce82089210785c5 to your computer and use it in GitHub Desktop.
Save snreid/66413ce82089210785c5 to your computer and use it in GitHub Desktop.
Attribute Before Cast Issue with Date

http://robots.thoughtbot.com/how-rails-works-type-casting I found this link very helpful.

I was having an issue validating a date. I needed the date to either match my format or be empty.

Here's what my validation looked like:

validate :expiration_date, format:{with: /(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])/}, allow_nil: true

For some reason, though, when the date was not in the right format, instead of kicking back an error it validated as if it was nil.

After some troubleshooting, I came to realize that was because the date WAS nil.

Turns out, Rails automagically casts values to match the attribute type when they are assigned to attribute (like record.id = "100", "100" (string) will be turned into an integer by rails).

For Date types, if the value doesn't match the required attribute formatting for casting, Rails lets it fail silently and returned nil.

I needed to capture what the value that was submitted, not what was cast, and thanks to the handy link above I learned you can use record.attribute_before_type_cast.

So in my case I had to make a custom validation method:

validate :validate_expiration_date

def validate_expiration_date
  if expiration_date_before_type_cast.present?
    unless expiration_date_before_type_cast.match(/(19|20)\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])/).present?\
      errors.add(:expiration_date, " date format must be YYYY-MM-DD.")
    end
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment