My model has a decimal amount attribute.
create_table :foos do |t|
t.decimal :amount
end
class Foo < ApplicationRecord
end
I always want the amount to be negative, so I add a normalisation:
class Foo < ApplicationRecord
normalizes :amount, with: -> amount { - amount.abs }
end
This seems to work perfectly.
Now, to be safe, I add a validation:
class Foo < ApplicationRecord
normalizes :amount, with: -> amount { - amount.abs }
validates :amount, numericality: {less_than: 0}
end
Now when I set the amount to a positive value, although the normalisation converts it to a negative value, the validator seems to think the value is still positive and adds a validation error.
foo = Foo.new amount: 4
foo.amount # => -4
foo.valid? # => false
foo.errors # => #<ActiveModel::Error attribute=amount, type=less_than, options={:value=>4, :count=>0}>
According to the tests for normalizes, normalisation happens before validation.
How can I get this to work?
Numericality validator seems to be specifically using raw value for validation without taking normalization into account:
https://github.com/rails/rails/blob/v7.1.3/activemodel/lib/active_model/validations/numericality.rb#L129
It needs to be this way because strings normalize to numbers (
"foo".to_d # => 0.0) so validation wouldn't work if it happened after normalization.You could write your own validation to bypass this problem: