So today I learned that if you have:
class Invoice < ActiveRecord::Base
has_many :transactions
before_save :cache_transaction_total
def cache_transaction_total
self.transaction_total = transactions.sum(:total) || 0
end
end
class Transaction < ActiveRecord::Base
belongs_to :invoice
end
And you open a rails console and do something innocuous like:
$ i = Invoice.create
The query that aggregates the transactions in the before_save callback is something like:
SELECT SUM("transactions"."total") AS sum_id
FROM "transactions" WHERE "transactions"."invoice_id" IS NULL
Which rather than aggregating all the (non-existant) transactions associated to the new invoice, aggregates all the transactions which aren't associated to an invoice at all - which gives a very different result. In my case, most transactions are not listed to an invoice so instead of caching 0
it caches something more like 1,000,000
.
I guess the solution is to run the update in an after_save callback instead -- but does this behaviour not seem completely different to what we would expect?
Thoughts?
Yeah I guess I see why it's happening I just thought that AR would catch that the id was null and not try and do the aggregation. After all, if you do
it doesn't go ahead and