我有两个类,存款和出价,它们关联为:
class Bid < ActiveRecord::Base
belongs_to :deposit
end
和
class Deposit < ActiveRecord::Base
has_many :bids
end
沉积物具有固定的量,其在创建时设定。出价也有金额,我正在尝试使用验证来确保bid.amount小于它所属的存款金额。
我尝试通过以下方式实现这一目标:
class Bid < ActiveRecord::Base
validates :amount, numericality: { only_integer: true, less_than_or_equal_to: self.deposit.amount }
end
但它给了我NoMethodError。我也尝试过使用代码块,但也无法使用它。我猜测问题的一部分是记录尚未完全创建,但我找不到有关该问题的任何信息。
如何根据相关记录值进行此类验证?
答案 0 :(得分:2)
通过validate
添加您自己的验证方法(注意:单数)。
class Bid < ActionRecord::Base
validate :my_thing
def my_thing
unless self.my_condition
errors.add :field, :message
end
end
end
请参阅http://guides.rubyonrails.org/active_record_validations.html#performing-custom-validations
答案 1 :(得分:0)
作为pduersteler says,您可以使用验证方法。这是特定于您的问题的一个:
class Bid < ActionRecord::Base
validates :amount, numericality: { only_integer: true }
validate :amount_not_more_than_deposit_amount
def amount_not_more_than_deposit_amount
if amount > deposit.amount
errors.add :amount, "cannot be greater than the deposit amount"
end
end
end
但是,当您基于关联对象中的值验证对象时,必须考虑如果该关联模型被编辑会发生什么情况。在这种情况下,投标金额永远不应大于关联的保证金金额,但是如果已经附加投标的保证金被编辑为较低金额,会发生什么情况。 ActiveRecord将允许此操作而不会发出任何警告或错误,因此,在验证Deposit
时要防止这种情况,您还应该验证所有关联的Bid
class Deposit < ActiveRecord::Base
has_many :bids
validate_associated :bids
end
这样,将某笔存款的金额设置为低于其中一个出价的存款将无效。这将为应用程序带来一些额外的健壮性。
这仍然可能失败的一种方法是在竞争条件下。在创建投标的同时更改存款金额。对Deposit
的验证会在出价创建完毕之前检查出价,因此不会对其进行考虑,但是Bid
正在创建过程中,其验证会检查{{1 }},然后再进行更改。两次验证均通过,然后创建了出价,并且存款金额更改为低于新出价的金额,并且创建了无效状态,没有任何错误或警告。
为避免这种情况,您需要在创建或更新出价时锁定Deposit
表中相关记录,相反,您需要锁定{{ 1}}表,而正在更新存款。