Rails ActiveRecord的:pluck和:map返回两个不同的值-为什么?

时间:2018-11-12 16:41:58

标签: ruby-on-rails ruby-on-rails-4 activerecord

我有一个ActiveRecord模型(使用STI)MonetaryChange::PaymentPromise,其中subtotal_cents作为属性/列(整数)。

我的控制器正在更新该模型/属性,但是由于某些原因,我在调用map时得到了旧的/原始值,而在调用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" = $1  [["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" = $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]]

有人知道为什么会这样吗,我该如何解决呢?

我尝试将.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必须在关联上做一些事情,这使它给了我唱片的旧版本。有什么想法吗?

1 个答案:

答案 0 :(得分:2)

好吧,重要的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的默认值。这是帮助我解决这个问题的线索。

谢谢大家的帮助!