Rails ActiveRecord :pluck 和 :map return 两个不同的值 - 为什么?
Rails ActiveRecord :pluck and :map return two different values - why?
我有一个 ActiveRecord 模型(使用 STI)MonetaryChange::PaymentPromise
,它具有 subtotal_cents
作为属性/列(整数)。
我的控制器正在更新 model/attribute,但由于某种原因,我在调用 map
时得到 old/original 值,在调用时得到更新(正确)的值pluck
。例如:
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
我注意到 Rails 为 pluck
方法生成的 SQL 要简单得多:
(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" = [["id", 1]]
但是 map
方法的 SQL 在第一次查询后加载了一大堆关联:
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" = [["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" = 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" = LIMIT 1 [["v410_ordered_sku_id", 1]]
V410Sku Load (0.2ms) SELECT "v410_skus".* FROM "v410_skus" WHERE "v410_skus"."id" = LIMIT 1 [["id", 1]]
知道为什么会这样吗?我该如何解决?
我尝试将 .reload
添加到我的查询中,但结果是一样的:
V410MonetaryChange::PaymentPromise.where(id: 1).reload.map(&:subtotal_cents)
=> [12300]
编辑 1:
我可以确认数据库具有正确的值 (24600)。当我打开 psql
控制台和 运行 查询时:
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;
我得到:
subtotal_cents
----------------
24600
(1 row)
所以 Rails 一定是对协会做了什么,导致它给我一个旧版本的记录。有什么想法吗?
好的,重要的 Rails 今天学到的教训!
我最近向这个模型添加了一个 after_initialize
回调,它为新初始化的记录设置了默认值(包括 subtotal_cents
)。
我没有意识到这个回调是重新-初始化(即加载后在内存中覆盖)现有记录默认值。
我的解决方法是更改
after_initialize :set_default_currency_amounts
到
after_initialize :set_default_currency_amounts, unless: Proc.new { |pp| pp.persisted? }
在我的例子中,这就是 SQL 这么长的原因 - 我的默认设置需要加载一些关联模型才能获得 subtotal_cents
的默认值。这是帮助我解决这个问题的线索。
感谢大家的帮助!
我有一个 ActiveRecord 模型(使用 STI)MonetaryChange::PaymentPromise
,它具有 subtotal_cents
作为属性/列(整数)。
我的控制器正在更新 model/attribute,但由于某种原因,我在调用 map
时得到 old/original 值,在调用时得到更新(正确)的值pluck
。例如:
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
我注意到 Rails 为 pluck
方法生成的 SQL 要简单得多:
(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" = [["id", 1]]
但是 map
方法的 SQL 在第一次查询后加载了一大堆关联:
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" = [["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" = 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" = LIMIT 1 [["v410_ordered_sku_id", 1]]
V410Sku Load (0.2ms) SELECT "v410_skus".* FROM "v410_skus" WHERE "v410_skus"."id" = LIMIT 1 [["id", 1]]
知道为什么会这样吗?我该如何解决?
我尝试将 .reload
添加到我的查询中,但结果是一样的:
V410MonetaryChange::PaymentPromise.where(id: 1).reload.map(&:subtotal_cents)
=> [12300]
编辑 1:
我可以确认数据库具有正确的值 (24600)。当我打开 psql
控制台和 运行 查询时:
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;
我得到:
subtotal_cents
----------------
24600
(1 row)
所以 Rails 一定是对协会做了什么,导致它给我一个旧版本的记录。有什么想法吗?
好的,重要的 Rails 今天学到的教训!
我最近向这个模型添加了一个 after_initialize
回调,它为新初始化的记录设置了默认值(包括 subtotal_cents
)。
我没有意识到这个回调是重新-初始化(即加载后在内存中覆盖)现有记录默认值。
我的解决方法是更改
after_initialize :set_default_currency_amounts
到
after_initialize :set_default_currency_amounts, unless: Proc.new { |pp| pp.persisted? }
在我的例子中,这就是 SQL 这么长的原因 - 我的默认设置需要加载一些关联模型才能获得 subtotal_cents
的默认值。这是帮助我解决这个问题的线索。
感谢大家的帮助!