2

我有 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 的问题,但我无法掌握如何使用它:(

4

3 回答 3

2

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

我认为这样的事情应该工作,使用before_add 回调

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
  ...
于 2012-07-19T07:49:43.443 回答
1

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

更一般地说,在相关模型上添加验证ActiveRecord效果不是很好。在某些情况下,这几乎是不可能的,而在其他情况下——很难做到正确。我想你已经看到它很容易出错。我建议避免它并尝试设计您的数据库,以便您不需要(Invoice#total在这种情况下作为一种方法)。

于 2012-07-19T09:29:55.240 回答
0

使用accepts_nested_attributes_for. 但答案只是说这很难,如果不是不可能的话!. accepts_nested_attributes_for是一种有点复杂的方法,但它有效 - 除非您尝试基于子模型的计算来验证模型。我可能已经找到了解决计算问题的方法。

我正在开发一个基于网络的复式记账应用程序,它具有以下基本模型;

class Account < ApplicationRecord
  has_many :splits
  has_many :entries, through: :splits
end

class Entry < ApplicationRecord
  has_many :splits, -> {order(:account_id)}, dependent: :destroy, inverse_of: :entry

  validate  :balanced?
end

class Split < ApplicationRecord
  belongs_to :entry, inverse_of: :splits
  belongs_to :account

  validates_associated :account
  validates_associated :entry
end

条目(交易)必须至少有两个拆分,拆分中的金额属性(或借方/贷方)之和必须等于 0。我虽然validate :balanced?会处理它,但明显的 Javascript 错误允许输入不平衡。我还没有找到错误,但由于条目不平衡,我无法更新它,因为valid?在我尝试添加的新拆分上不起作用(返回 false)。

分类帐accepts_nested_attributes_for表单已经退出了一些不应允许提交不平衡交易的 Javascript。均衡?创建时未设置错误,但更新时出现错误。我修复它的方法不是使用不起作用的验证,而是依赖与以下方法一起调用的方法@entry.update(entry_params)

class Entry < ApplicationRecord
  has_many :splits, -> {order(:account_id)}, dependent: :destroy, inverse_of: :entry

  # validate  :balanced? # took this out since its after the fact, balanced? method can still be called

  accepts_nested_attributes_for :splits, 
    :reject_if =>  proc { |att| att[:amount].to_i.zero? && att['account_id'].to_i.zero?},
    allow_destroy: true

    def valid_params?(params)
      split_sum = 0
      params_hash = params.to_h
      params_hash[:splits_attributes].each{|k,s| split_sum += s[:amount].to_i if s[:_destroy].to_i.zero?}
      unless split_sum.zero?
        errors.add(:amount, "Unbalanced: debits, credits must balance")
        return false
      else
        return true
      end
    end
  end
end

# update action from Entry Controller

def update
  respond_to do |format|
    if @entry.valid_params?(entry_params) && @entry.update(entry_params)
      format.html { redirect_to account_path(session[:current_acct]), notice: 'Entry was successfully updated.' }
      format.json { render :show, status: :ok, location: @entry }
    else
      # ... errr
    end
  end
end

同样,这只不过是验证参数与不适用于这种情况的模型验证。

这可能与答案 2 大致相同,但不使用回调,只是调用控制器

于 2018-12-30T18:48:55.233 回答