11

I have an object with an attribute called value which is of type big decimal. In the class definition i have validates_numericality_of.

However if i:

a.value = 'fire'

'fire' ends up getting typecast to the correct type before the validation fires so:

a.valid? => true

How do get the validation to fire before the typecast?

Thanks

Dan

Dan Galipo
  • 268
  • 3
  • 8

2 Answers2

16

From ActiveRecord::Base docs:

Sometimes you want to be able to read the raw attribute data without having the column-determined typecast run its course first. That can be done by using the <attribute>_before_type_cast accessors that all attributes have. For example, if your Account model has a balance attribute, you can call account.balance_before_type_cast or account.id_before_type_cast.

This is especially useful in validation situations where the user might supply a string for an integer field and you want to display the original string back in an error message. Accessing the attribute normally would typecast the string to 0, which isn’t what you want.

Mladen Jablanović
  • 43,461
  • 10
  • 90
  • 113
  • 2
    Fyi, if you want to do this without getting weird validation messages in your views. E.g. " before type cast must be a number" you can create a [custom validator](http://guides.rubyonrails.org/active_record_validations_callbacks.html#custom-validators) that checks `"#{attribute}_before_type_cast"` instead of just checking the attribute itself. – Ajedi32 May 02 '13 at 21:28
  • @Ajedi32 Or pass :message option to validator? – sheerun Jan 18 '14 at 21:49
  • 2
    @sheerun No, that won't work because the message option doesn't change what attribute the validation error is associated with. (E.g. In " before type cast must be a number", you could only use that option to change the "must be a number" part of the message.) – Ajedi32 Jan 20 '14 at 14:02
1

A new gem has been created to help validate types in rails.

An explanatory blog post exists to answer more of the "why" it was created in the first place.

With this library your code could be:

class SomeObject < ActiveRecord::Base
  validates_type :value, :big_decimal
end

This will throw an exception when anything except a float is assigned to value instead of quietly casting the value to a BigDecimal and saving it.

yez
  • 2,368
  • 9
  • 15