2012-07-19 50 views
1

我有2种型号:验证该部分的总和等于与父母总/儿童记录

Invoice has_many :lines 

Line belongs_to :invoice 

我想确保Line对于给定Invoice比赛总的总和相关的Invoice

我已经试过这样:

validate :total_amount 
def total_amount 
    inv_id = self.invoice_id 
    target_amount = Invoice.find(inv_id).total 
    total_lines = Line.where(invoice_id: inv_id).sum(:line_value) 

    errors.add(:total, " should be lower or equal to the total amount of the invoice") if total_lines > target_amount 
end 

  1. 它并不适用于新的对象(只更新)工作
  2. 甚至更​​新系统地抛出一个错误

我也看到一个关于AssociatedValidator的问题,但我还没有能够掌握如何使用:(

回答

1

我可能解释是错误的,但如果totalinvoices表中的列,我建议删除它。相反,请将其作为一种方法,并使方法将价格加上任何调整。否则,您在数据库中有重复。这样你就不需要再验证任何东西:)

在更一般的说明中,在关联模型ActiveRecord上添加验证工作不太好。在某些情况下,这几乎是不可能的,而在其他情况下 - 很难做到正确。我认为你已经看到它很容易出错。我建议避免它,并试图设计你的数据库,这样你就不需要(在这种情况下有Invoice#total作为一种方法)。

2

目前尚不清楚您要验证的是什么,因为您的示例与之前描述的不同。

我觉得这样的事情应该工作,使用before_add callback

class Invoice < AR::Base 
    has_many :lines, :before_add => :validate_total 

    def validate_total(invoice, line) 
    totals = invoice.lines.sum(:line_value) 

    if totals + line.line_value > invoice.total 
     invoice.errors.add(:total, " should be lower or equal to the total amount of the invoice") 
     return false # I think you can alternatively raise an exception here 
    end 
    ...