December, 2010

Dec 10

Rails custom validation before ActiveRecord typecasting

Rails 3 validation framework, extracted from ActiveRecord and now a part of ActiveModel is pretty sleek. As anything else rails (consider it good or bad) it offers sensible defaults. Most stuff in rails is also easily configurable/customizable. Validations is one such thing, but I think it needs more documentation.

I ran into a problem trying to validate a date field (defined in ActiveRecord) as:

Rails also doesn’t have a built-in date validation, but it’s easy enough to either provide your own validator method or create a reusable validator. I opted for the later, as I might need to reuse the same validator across the site.

So running this with any invalid date value, like say 11111111111 which gets parsed by Date.parse method didn’t yield an error, actually it never even invoked the validator.

After a bit of digging, I figured out that it has to do with the lifecycle of ActiveRecord, basically it tries to typecast the value to the value defined in migrations. Typecasting invalid values like above causes ActiveRecord to set the value to nil (not sure why yet, will dig into source code later). Because the validator isn’t invoked on nil values, unless you specifically tell it to not allow nil with :allow_nil => false, the validate_each method is bypassed. You can see the logic for yourself in the validate method.

In order to fix this issue, you have to access the raw value that’s kept around after the typecast. I turned this into a reusable class, though if the validator that needs to operate on the raw (uncasted) value, you just inherit from this class. Here is the class…

Now the DataValidator above just need to inherit from RawEachValidator and you’re all set.