gpt4 book ai didi

ruby-on-rails - Rails 在使用 include 进行预缓存时忽略关联范围

转载 作者:数据小太阳 更新时间:2023-10-29 06:41:44 27 4
gpt4 key购买 nike

TL;DR:这个问题在 https://github.com/skensell/SO-question-example 有自己的示例应用程序你可以用它来调试自己。我已经在这个问题上悬赏过一次,但我不相信(或者我不理解)顶级回答者的推理。我打算再悬赏一次,因为它让我很沮丧。

原始问题

我有一个模型User,它有一个像这样的关联:

has_many :avatars, -> { order([:sort_order => :asc,:created_at => :asc])}

我有一个端点,它执行用户搜索并设置一个 @users 变量以供 View 使用。这是我在调试器中发现的诡异部分:

@users.first.avatars[0..2].map(&:id)
# => [2546, 2547, 2548]
# This is the correct order.

@users.to_a.first.avatars[0..2].map(&:id)
# => [2548, 2546, 2547]
# Wrong order.

这是怎么回事?

唯一的区别是to_a。我什至尝试省略 to_a,但我认为它无论如何都会被 jbuilder 隐式调用,因为我将它设置为 json 数组。

也许我搜索 User 的方式与它有关?我正在使用多个包含和连接。

更新

在这里,我可以向您展示一个来自 Rails 控制台的奇怪行为的简单示例。似乎 includes..references 是违规者,但我不明白为什么或如何。

User.order(id: :desc)
.includes(:avatars, :industries)
.where(industries: {id: [5]})
.references(:industries)
.limit(5).to_a.second.avatars.map(&:id)
# => [2751, 2748, 2749]
# Wrong order.

User.order(id: :desc)
.includes(:avatars, :industries)
.where(industries: {id: [5]})
.references(:industries)
.limit(5).second.avatars.map(&:id)
# => [2748, 2749, 2751]
# Correct order.

我可以验证这些查询指的是同一个用户,并且标记为 Correct order 的那个确实是正确的 w.r.t sort_ordercreated_at(这是关联指定的方式顺序)。

更新 2

附件是请求的 SQL 日志。我将不相关的字段更改为“OMITTED”,并将 34 个不相关的用户字段替换为“...”。

>> User.order(id: :desc).includes(:avatars, :industries).where(industries: {id:  [5]}).references(:industries).limit(5).to_a.second.avatars.map(&:id)
SQL (18.5ms) SELECT DISTINCT "users"."id", "users"."id" AS alias_0 FROM "users" LEFT OUTER JOIN "avatars" ON "avatars"."user_id" = "users"."id" LEFT OUTER JOIN "user_professions" ON "user_professions"."user_id" = "users"."id" LEFT OUTER JOIN "industries" ON "industries"."id" = "user_professions"."industry_id" WHERE "industries"."id" IN (5) ORDER BY "users"."id" DESC LIMIT 5
SQL (8.3ms) SELECT "users"."id" AS t0_r0, "users"."OMITTED" AS t0_r1, "users"."OMITTED" AS t0_r2, ... AS t0_r36, "avatars"."id" AS t1_r0, "avatars"."user_id" AS t1_r1, "avatars"."avatar" AS t1_r2, "avatars"."created_at" AS t1_r3, "avatars"."updated_at" AS t1_r4, "avatars"."OMITTED" AS t1_r5, "avatars"."OMITTED" AS t1_r6, "avatars"."sort_order" AS t1_r7, "industries"."id" AS t2_r0, "industries"."name" AS t2_r1, "industries"."created_at" AS t2_r2, "industries"."updated_at" AS t2_r3 FROM "users" LEFT OUTER JOIN "avatars" ON "avatars"."user_id" = "users"."id" LEFT OUTER JOIN "user_professions" ON "user_professions"."user_id" = "users"."id" LEFT OUTER JOIN "industries" ON "industries"."id" = "user_professions"."industry_id" WHERE "industries"."id" IN (5) AND "users"."id" IN (1526, 945, 927, 888, 884) ORDER BY "users"."id" DESC
=> [2751, 2748, 2749]

>> User.order(id: :desc).includes(:avatars, :industries).where(industries: {id: [5]}).references(:industries).limit(5).second.avatars.map(&:id)
SQL (0.9ms) SELECT DISTINCT "users"."id", "users"."id" AS alias_0 FROM "users" LEFT OUTER JOIN "avatars" ON "avatars"."user_id" = "users"."id" LEFT OUTER JOIN "user_professions" ON "user_professions"."user_id" = "users"."id" LEFT OUTER JOIN "industries" ON "industries"."id" = "user_professions"."industry_id" WHERE "industries"."id" IN (5) ORDER BY "users"."id" DESC LIMIT 1 OFFSET 1
SQL (0.8ms) SELECT "users"."id" AS t0_r0, "users"."OMITTED" AS t0_r1, "users"."OMITTED" AS t0_r2, ... AS t0_r36, "avatars"."id" AS t1_r0, "avatars"."user_id" AS t1_r1, "avatars"."avatar" AS t1_r2, "avatars"."created_at" AS t1_r3, "avatars"."updated_at" AS t1_r4, "avatars"."OMITTED" AS t1_r5, "avatars"."OMITTED" AS t1_r6, "avatars"."sort_order" AS t1_r7, "industries"."id" AS t2_r0, "industries"."name" AS t2_r1, "industries"."created_at" AS t2_r2, "industries"."updated_at" AS t2_r3 FROM "users" LEFT OUTER JOIN "avatars" ON "avatars"."user_id" = "users"."id" LEFT OUTER JOIN "user_professions" ON "user_professions"."user_id" = "users"."id" LEFT OUTER JOIN "industries" ON "industries"."id" = "user_professions"."industry_id" WHERE "industries"."id" IN (5) AND "users"."id" IN (945) ORDER BY "users"."id" DESC
=> [2748, 2749, 2751]
>>

在这里,我将附上一个日志,其中显示了相关用户的头像(id、sort_order 和 created_at),因此您可以看到顺序应该是确定的。

>> User.find(945).avatars.pluck(:id,:sort_order,:created_at)
User Load (5.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 945]]
(0.2ms) SELECT "avatars"."id", "avatars"."sort_order", "avatars"."created_at" FROM "avatars" WHERE "avatars"."user_id" = $1 ORDER BY "avatars"."sort_order" ASC, "avatars"."created_at" ASC [["user_id", 945]]
=> [[2748, 0, Fri, 13 Nov 2015 00:32:53 UTC +00:00], [2749, 0, Fri, 13 Nov 2015 00:47:02 UTC +00:00], [2751, 0, Fri, 13 Nov 2015 00:48:05 UTC +00:00]]

此外,我正在使用 Rails 4.1.4 和 Ruby 2.1.10。

更新 3

我在这里创建了一个示例应用程序:https://github.com/skensell/SO-question-example .在此示例应用程序中更奇怪的是 to_a 甚至都不重要。即使只有 includes... references,我也会得到错误的顺序。

最佳答案

@users.first.avatars[0..2].map(&:id)
# => [2546, 2547, 2548]

@users.to_a.first.avatars[0..2].map(&:id)
# => [2548, 2546, 2547]
  • What is going on here?

没有错。

根据 Guide Retrieving a Single Object Section: 1.1.3 #first

The first method finds the first record ordered by primary key (default)

SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1

接下来的方法作为集合返回 @users.to_a order by updated_at

希望对你有帮助!

关于ruby-on-rails - Rails 在使用 include 进行预缓存时忽略关联范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39359361/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com