我的模型有小数金额属性。
create_table :foos do |t|
t.decimal :amount
end
class Foo < ApplicationRecord
end
我总是希望金额为负数,所以我添加了标准化:
class Foo < ApplicationRecord
normalizes :amount, with: -> amount { - amount.abs }
end
这似乎工作得很好。
现在,为了安全起见,我添加了一个验证:
class Foo < ApplicationRecord
normalizes :amount, with: -> amount { - amount.abs }
validates :amount, numericality: {less_than: 0}
end
现在,当我将金额设置为正值时,尽管标准化将其转换为负值,但验证器似乎认为该值仍然是正值并添加了验证错误。
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}>
根据
normalizes
的测试,标准化发生在验证之前。
我怎样才能让它发挥作用?
数值验证器似乎专门使用原始值进行验证:
https://github.com/rails/rails/blob/v7.1.3/activemodel/lib/active_model/validations/numericality.rb#L129
if record.respond_to?(came_from_user)
if record.public_send(came_from_user)
raw_value = record.public_send(:"#{attr_name}_before_type_cast")
不知道这是另一个错误还是故意的。您可以编写自己的验证来绕过此问题:
validate do
errors.add(:amount, :less_than, value: amount, count: 0) unless amount.negative?
end