为什么 Rails 验证器不使用标准化值?

问题描述 投票:0回答:1

我的模型有小数金额属性。

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
的测试,标准化发生在验证之前

我怎样才能让它发挥作用?

ruby-on-rails activerecord
1个回答
0
投票

数值验证器似乎专门使用原始值进行验证:
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
© www.soinside.com 2019 - 2024. All rights reserved.