1

我正在记录财务Interactions,建模为偶数,LedgerEntries并且每个Interaction总和必须为零。

class Interaction < ActiveRecord::Base
  has_many :entries, class_name: 'LedgerEntry'

  validate :entries_must_sum_to_zero

  def balance
    credit = self.entries.sum(:credit)
    debit = self.entries.sum(:debit)
    return credit - debit
  end

  protected

  def entries_must_sum_to_zero
    if self.entries.count.odd?
      errors.add(:entries, "There must be an even number of entries.")
    end
    if self.balance != 0
      errors.add(:entries, "Entries must sum to zero.")
    end
  end
end

class LedgerEntry < ActiveRecord::Base
  validates_numericality_of :credit, greater_than_or_equal_to: 0
  validates_numericality_of :debit, greater_than_or_equal_to: 0
  belongs_to :interaction

  validate :one_of_credit_or_debit

  protected

  def one_of_credit_or_debit
    if self.credit != 0 && self.debit != 0
      errors.add(:credit, "You can't assign both a credit and debit to the one entry.")
    end
  end
end

我遇到的问题是这个测试永远不会失败。

it "should complain if an Interaction's balance is non-zero" do
  d = LedgerEntry.create!(credit: 50.0)
  expect {Interaction.create!(entries: [d])}.to raise_error ActiveRecord::RecordInvalid
end

在执行期间entries_must_sum_to_zero self.entries.count始终为 0 并self.balance始终返回 0。

如何在验证方法运行之前强制使用条目?

4

2 回答 2

1

在您的验证中,您正在使用数据库操作进行验证(即countand sum),但条目尚未存储到数据库中,并且直到保存后Interaction才会存储,并且它们可以与它们的外键一起存储.

但是,由于代理entries的魔力,仍然可以访问和操作该属性。ActiveRecord您只需要使用不依赖于进入数据库的操作,例如lengthinstead ofcountto_a.map(&:<attribute>).inject(&:+)instead of,sum如:

  def balance
    credit = self.entries.to_a.map(&:credit).inject(&:+)
    debit = self.entries.to_a.map(&:debit).inject(&:+)
    return credit - debit
  end
于 2013-09-03T06:00:19.433 回答
0

尝试像这样测试它:

it "should complain if an Interaction's balance is non-zero" do
  entry = LedgerEntry.new(:credit => 50.0)
  interaction = Interaction.new(:entries => [entry])
  expect {interaction.valid?}.to raise_error ActiveRecord::RecordInvalid
end
于 2013-09-03T01:26:14.267 回答