我会更改字段名称。但是鉴于当前的数据库模式,请尝试以下代码:
应用程序/模型/发票.rb
class Invoice < ActiveRecord::Base
has_many :payments
def still_open_amount
self.amount_payable_in_cents - self.payments.sum('amount_in_cents')
end
end
应用程序/模型/payment.rb
class Payment < ActiveRecord::Base
belongs_to :invoice
validates :amount_in_cents, :numericality => { :greater_than => 0 }
before_validation :check_all_payments
private
def check_all_payments
if self.new_record?
if (self.invoice.payments.sum('amount_in_cents') + self.amount_in_cents) > self.invoice.amount_payable_in_cents
errors.add(:amount, 'the invoice would be overpaid')
end
else
if (self.invoice.payments.sum('amount_in_cents') - self.amount_in_cents_was + self.amount_in_cents) > self.invoice.amount_payable_in_cents
errors.add(:amount, 'the invoice would be overpaid')
end
end
end
end
如果您尝试创建多付的付款,这将通过验证错误:
~/Desktop/testapp ᐅ rails c
Loading development environment (Rails 4.0.0.beta1)
1.9.3-p286 :001 > i = Invoice.create(amount_payable_in_cents: 100)
(0.1ms) begin transaction
SQL (6.8ms) INSERT INTO "invoices" ("amount_payable_in_cents", "created_at", "updated_at") VALUES (?, ?, ?) [["amount_payable_in_cents", 100], ["created_at", Mon, 13 May 2013 19:23:24 UTC +00:00], ["updated_at", Mon, 13 May 2013 19:23:24 UTC +00:00]]
(0.8ms) commit transaction
=> #<Invoice id: 1, amount_payable_in_cents: 100, created_at: "2013-05-13 19:23:24", updated_at: "2013-05-13 19:23:24">
1.9.3-p286 :003 > p1 = i.payments.create(amount_in_cents: 90)
(0.1ms) begin transaction
Invoice Load (0.2ms) SELECT "invoices".* FROM "invoices" WHERE "invoices"."id" = ? ORDER BY "invoices"."id" ASC LIMIT 1 [["id", 1]]
(0.2ms) SELECT SUM("payments"."amount_in_cents") AS sum_id FROM "payments" WHERE "payments"."invoice_id" = ? [["invoice_id", 1]]
SQL (0.4ms) INSERT INTO "payments" ("amount_in_cents", "created_at", "invoice_id", "updated_at") VALUES (?, ?, ?, ?) [["amount_in_cents", 90], ["created_at", Mon, 13 May 2013 19:24:10 UTC +00:00], ["invoice_id", 1], ["updated_at", Mon, 13 May 2013 19:24:10 UTC +00:00]]
(1.0ms) commit transaction
=> #<Payment id: 1, invoice_id: 1, amount_in_cents: 90, created_at: "2013-05-13 19:24:10", updated_at: "2013-05-13 19:24:10">
1.9.3-p286 :004 > p2 = i.payments.create(amount_in_cents: 20)
(0.1ms) begin transaction
Invoice Load (0.2ms) SELECT "invoices".* FROM "invoices" WHERE "invoices"."id" = ? ORDER BY "invoices"."id" ASC LIMIT 1 [["id", 1]]
(0.1ms) SELECT SUM("payments"."amount_in_cents") AS sum_id FROM "payments" WHERE "payments"."invoice_id" = ? [["invoice_id", 1]]
(0.1ms) commit transaction
=> #<Payment id: nil, invoice_id: 1, amount_in_cents: 20, created_at: nil, updated_at: nil>
1.9.3-p286 :005 > p2.errors
=> #<ActiveModel::Errors:0x007fd57b8e36d8 @base=#<Payment id: nil, invoice_id: 1, amount_in_cents: 20, created_at: nil, updated_at: nil>, @messages={:amount=>["the invoice would be overpaid"]}>
1.9.3-p286 :006 >