Reputation: 964
I have an ActiveRecord model (using STI) MonetaryChange::PaymentPromise
that has subtotal_cents
as an attribute / column (an integer).
My controller is updating that model/attribute, but for some reason, I'm getting the old/original value when I call map
and the updated (correct) value when I call pluck
. For example:
V410MonetaryChange::PaymentPromise.where(id: 1).pluck(:subtotal_cents)
=> [24600] # this is the correct updated value
V410MonetaryChange::PaymentPromise.where(id: 1).map(&:subtotal_cents)
=> [12300] # this is the original value, but it should have been updated to 24600
I notice that the SQL that Rails generates for the pluck
method is much simpler:
(0.5ms) SELECT "v410_monetary_changes"."subtotal_cents"
FROM "v410_monetary_changes"
WHERE "v410_monetary_changes"."type" IN ('V410MonetaryChange::PaymentPromise')
AND "v410_monetary_changes"."deleted_at" IS NULL
AND "v410_monetary_changes"."id" = $1 [["id", 1]]
but the SQL for the map
method loads a whole bunch of associations after the first query:
V410MonetaryChange::PaymentPromise Load (0.6ms) SELECT "v410_monetary_changes".* FROM "v410_monetary_changes" WHERE "v410_monetary_changes"."type" IN ('V410MonetaryChange::PaymentPromise') AND "v410_monetary_changes"."deleted_at" IS NULL AND "v410_monetary_changes"."id" = $1 [["id", 1]]
V410OrderedSku Load (0.3ms) SELECT "v410_ordered_skus".* FROM "v410_ordered_skus" WHERE "v410_ordered_skus"."deleted_at" IS NULL AND "v410_ordered_skus"."id" = $1 LIMIT 1 [["id", 1]]
V410OrderedSkusV410Sku Load (0.2ms) SELECT "v410_ordered_skus_v410_skus".* FROM "v410_ordered_skus_v410_skus" WHERE "v410_ordered_skus_v410_skus"."v410_ordered_sku_id" = $1 LIMIT 1 [["v410_ordered_sku_id", 1]]
V410Sku Load (0.2ms) SELECT "v410_skus".* FROM "v410_skus" WHERE "v410_skus"."id" = $1 LIMIT 1 [["id", 1]]
Any idea why this is the case, and how I can resolve this?
I tried adding .reload
to my query, but the results were the same:
V410MonetaryChange::PaymentPromise.where(id: 1).reload.map(&:subtotal_cents)
=> [12300]
Edit 1:
I can confirm that the database has the correct value (24600). When I open a psql
console, and run the query:
SELECT "v410_monetary_changes"."subtotal_cents"
FROM "v410_monetary_changes"
WHERE "v410_monetary_changes"."type" IN ('V410MonetaryChange::PaymentPromise')
AND "v410_monetary_changes"."deleted_at" IS NULL
AND "v410_monetary_changes"."id" = 1;
I get:
subtotal_cents
----------------
24600
(1 row)
So Rails must be doing something with the associations that is causing it to give me an old version of the record. Any ideas why?
Upvotes: 1
Views: 1651
Reputation: 964
OK, important Rails lesson learned today!
I recently added an after_initialize
callback to this model, which set the default values (including subtotal_cents
) for newly initialized records.
What I didn't realise is that this callback was re-initializing (ie overwriting in memory after load) existing records with the default values.
My fix was to change
after_initialize :set_default_currency_amounts
to
after_initialize :set_default_currency_amounts, unless: Proc.new { |pp| pp.persisted? }
In my case, this is why the SQL was so long - my defaults required the loading of some associated models to get the default value for subtotal_cents
. This was the clue that helped me solve this.
Thank you to everyone for your help!
Upvotes: 2