Ответ 1
Включает в себя порядок родительской таблицы, записи которой будут извлекаться только тогда, когда она приведет к запросу соединения. т.е. в приведенном выше случае заказ аватаров будет пропущен, и пользовательский заказ будет использоваться, когда запрос включает результат в соединение. Вы можете добавить область по умолчанию для пользователя и подтвердить.
Если вы по-прежнему хотите, чтобы user.avatars сортировались в соответствии с заданными аватарами, вам нужно заменить include с помощью соединений. Обратите внимание, что использование соединения будет извлекать повторяющиеся записи пользователя.
Рабочее решение для извлечения данных, как и ожидалось, должно использовать объединения и включает вместе.
Loading development environment (Rails 4.1.4)
2.2.0 :001 > User.count
(0.1ms) SELECT COUNT(*) FROM "users"
=> 2
2.2.0 :002 > User.pluck :id, :name
(0.2ms) SELECT "users"."id", "users"."name" FROM "users"
=> [[1, "John"], [2, "Jill"]]
2.2.0 :003 > User.first.industries.pluck :id, :name
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
(0.2ms) SELECT "industries"."id", "industries"."name" FROM "industries" INNER JOIN "user_industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "user_industries"."user_id" = ? [["user_id", 1]]
=> [[1, "Art"], [2, "Music"]]
2.2.0 :004 > User.last.industries.pluck :id, :name
User Load (1.4ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
(0.2ms) SELECT "industries"."id", "industries"."name" FROM "industries" INNER JOIN "user_industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "user_industries"."user_id" = ? [["user_id", 2]]
=> [[1, "Art"]]
2.2.0 :005 > User.first.avatars.pluck :id, :sort_order
User Load (0.4ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
(0.3ms) SELECT "avatars"."id", "avatars"."sort_order" FROM "avatars" WHERE "avatars"."user_id" = ? ORDER BY "avatars"."sort_order" ASC, "avatars"."created_at" ASC [["user_id", 1]]
=> [[1, 0], [3, 1], [2, 2]]
2.2.0 :006 > User.last.avatars.pluck :id, :sort_order
User Load (4.1ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
(0.2ms) SELECT "avatars"."id", "avatars"."sort_order" FROM "avatars" WHERE "avatars"."user_id" = ? ORDER BY "avatars"."sort_order" ASC, "avatars"."created_at" ASC [["user_id", 2]]
=> [[4, 5], [6, 6], [5, 7]]
2.2.0 :007 > ap User.joins(:avatars, :industries).where(industries: {id: [1]}).references(:industries).count
(0.2ms) SELECT COUNT(*) FROM "users" INNER JOIN "avatars" ON "avatars"."user_id" = "users"."id" INNER JOIN "user_industries" ON "user_industries"."user_id" = "users"."id" INNER JOIN "industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "industries"."id" IN (1)
6
=> nil
2.2.0 :008 > ap User.joins(:avatars, :industries).where(industries: {id: [1]}).references(:industries).uniq.count
(0.3ms) SELECT DISTINCT COUNT(DISTINCT "users"."id") FROM "users" INNER JOIN "avatars" ON "avatars"."user_id" = "users"."id" INNER JOIN "user_industries" ON "user_industries"."user_id" = "users"."id" INNER JOIN "industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "industries"."id" IN (1)
2
=> nil
2.2.0 :009 > ap User.joins(:industries).where(industries: {id: [1]}).references(:industries).count
(0.3ms) SELECT COUNT(*) FROM "users" INNER JOIN "user_industries" ON "user_industries"."user_id" = "users"."id" INNER JOIN "industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "industries"."id" IN (1)
2
=> nil
2.2.0 :010 > User.joins(:industries).where(industries: {id: [1]}).references(:industries).each{|user| ap user.avatars }
User Load (0.3ms) SELECT "users".* FROM "users" INNER JOIN "user_industries" ON "user_industries"."user_id" = "users"."id" INNER JOIN "industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "industries"."id" IN (1)
Avatar Load (0.2ms) SELECT "avatars".* FROM "avatars" WHERE "avatars"."user_id" = ? ORDER BY "avatars"."sort_order" ASC, "avatars"."created_at" ASC [["user_id", 1]]
[
[0] #<Avatar:0x007ff03f8ab448> {
:id => 1,
:user_id => 1,
:sort_order => 0,
:created_at => Tue, 04 Oct 2016 07:05:36 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:44 UTC +00:00
},
[1] #<Avatar:0x007ff03ec7e4e0> {
:id => 3,
:user_id => 1,
:sort_order => 1,
:created_at => Tue, 04 Oct 2016 07:05:40 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:40 UTC +00:00
},
[2] #<Avatar:0x007ff03ec7e2d8> {
:id => 2,
:user_id => 1,
:sort_order => 2,
:created_at => Tue, 04 Oct 2016 07:05:38 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:42 UTC +00:00
}
]
Avatar Load (0.2ms) SELECT "avatars".* FROM "avatars" WHERE "avatars"."user_id" = ? ORDER BY "avatars"."sort_order" ASC, "avatars"."created_at" ASC [["user_id", 2]]
[
[0] #<Avatar:0x007ff03f9121e8> {
:id => 4,
:user_id => 2,
:sort_order => 5,
:created_at => Tue, 04 Oct 2016 07:05:44 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:48 UTC +00:00
},
[1] #<Avatar:0x007ff03f911fe0> {
:id => 6,
:user_id => 2,
:sort_order => 6,
:created_at => Tue, 04 Oct 2016 07:05:48 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:48 UTC +00:00
},
[2] #<Avatar:0x007ff03f911dd8> {
:id => 5,
:user_id => 2,
:sort_order => 7,
:created_at => Tue, 04 Oct 2016 07:05:46 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:48 UTC +00:00
}
]
=> [#<User id: 1, name: "John", created_at: "2016-10-04 07:05:40", updated_at: "2016-10-04 07:05:40">, #<User id: 2, name: "Jill", created_at: "2016-10-04 07:05:48", updated_at: "2016-10-04 07:05:48">]
2.2.0 :011 > User.joins(:industries).where(industries: {id: [1]}).references(:industries).includes(:avatars).each{|user| ap user.avatars }
User Load (0.3ms) SELECT "users".* FROM "users" INNER JOIN "user_industries" ON "user_industries"."user_id" = "users"."id" INNER JOIN "industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "industries"."id" IN (1)
Avatar Load (0.2ms) SELECT "avatars".* FROM "avatars" WHERE "avatars"."user_id" IN (1, 2) ORDER BY "avatars"."sort_order" ASC, "avatars"."created_at" ASC
[
[0] #<Avatar:0x007ff03c7f0df8> {
:id => 1,
:user_id => 1,
:sort_order => 0,
:created_at => Tue, 04 Oct 2016 07:05:36 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:44 UTC +00:00
},
[1] #<Avatar:0x007ff03c7f0bf0> {
:id => 3,
:user_id => 1,
:sort_order => 1,
:created_at => Tue, 04 Oct 2016 07:05:40 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:40 UTC +00:00
},
[2] #<Avatar:0x007ff03c7f09c0> {
:id => 2,
:user_id => 1,
:sort_order => 2,
:created_at => Tue, 04 Oct 2016 07:05:38 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:42 UTC +00:00
}
]
[
[0] #<Avatar:0x007ff03c7f07b8> {
:id => 4,
:user_id => 2,
:sort_order => 5,
:created_at => Tue, 04 Oct 2016 07:05:44 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:48 UTC +00:00
},
[1] #<Avatar:0x007ff03c7f0588> {
:id => 6,
:user_id => 2,
:sort_order => 6,
:created_at => Tue, 04 Oct 2016 07:05:48 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:48 UTC +00:00
},
[2] #<Avatar:0x007ff03c7f0380> {
:id => 5,
:user_id => 2,
:sort_order => 7,
:created_at => Tue, 04 Oct 2016 07:05:46 UTC +00:00,
:updated_at => Tue, 04 Oct 2016 07:05:48 UTC +00:00
}
]
=> [#<User id: 1, name: "John", created_at: "2016-10-04 07:05:40", updated_at: "2016-10-04 07:05:40">, #<User id: 2, name: "Jill", created_at: "2016-10-04 07:05:48", updated_at: "2016-10-04 07:05:48">]
В принципе, у нас есть две функции загрузки: preload и eager_load. Когда вы используете include, он либо вызывает preload, либо eager_load. предварительная загрузка результатов в 2 запроса (поиск пользователей и поиск аватаров для получаемых пользователей) wheres eager_load использует только 1 запрос (запрос соединения). Таким образом, когда включает результаты в запрос соединения (т.е. Результаты в eager_load), порядок получаемых ассоциаций пропускается с момента его единственного запроса.
User.includes(:avatars, :industries).where(industries: {id: [1]}).references(:industries)
приводит к соединению, потому что вы фильтруете пользователей на основе определенных отраслей, которые сами по себе являются "сквозной" ассоциацией. "через" использует соединение. Кроме того, помните, что "join" приводит к INNER JOIN, тогда как eager_load использует LEFT OUTER JOIN.
2.2.0 :050 > User.joins(:industries).where(industries: {id: [1]}).references(:industries)
User Load (0.2ms) SELECT "users".* FROM "users" INNER JOIN "user_industries" ON "user_industries"."user_id" = "users"."id" INNER JOIN "industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "industries"."id" IN (1)
=> #<ActiveRecord::Relation [#<User id: 1, name: "John", created_at: "2016-10-04 07:05:40", updated_at: "2016-10-04 07:05:40">, #<User id: 2, name: "Jill", created_at: "2016-10-04 07:05:48", updated_at: "2016-10-04
2.2.0 :054 > User.includes(:industries).where(industries: {id: [1]}).references(:industries)
SQL (0.3ms) SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "users"."created_at" AS t0_r2, "users"."updated_at" AS t0_r3, "industries"."id" AS t1_r0, "industries"."name" AS t1_r1, "industries"."created_at" AS t1_r2, "industries"."updated_at" AS t1_r3 FROM "users" LEFT OUTER JOIN "user_industries" ON "user_industries"."user_id" = "users"."id" LEFT OUTER JOIN "industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "industries"."id" IN (1)
=> #<ActiveRecord::Relation [#<User id: 1, name: "John", created_at: "2016-10-04 07:05:40", updated_at: "2016-10-04 07:05:40">, #<User id: 2, name: "Jill", created_at: "2016-10-04 07:05:48", updated_at: "2016-10-04 07:05:48">]>
2.2.0 :057 > User.eager_load(:industries).where(industries: {id: [1]}).references(:industries)
SQL (0.3ms) SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "users"."created_at" AS t0_r2, "users"."updated_at" AS t0_r3, "industries"."id" AS t1_r0, "industries"."name" AS t1_r1, "industries"."created_at" AS t1_r2, "industries"."updated_at" AS t1_r3 FROM "users" LEFT OUTER JOIN "user_industries" ON "user_industries"."user_id" = "users"."id" LEFT OUTER JOIN "industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "industries"."id" IN (1)
=> #<ActiveRecord::Relation [#<User id: 1, name: "John", created_at: "2016-10-04 07:05:40", updated_at: "2016-10-04 07:05:40">, #<User id: 2, name: "Jill", created_at: "2016-10-04 07:05:48", updated_at: "2016-10-04 07:05:48">]>
Вы можете сослаться на http://blog.arkency.com/2013/12/rails4-preloading/ для получения дополнительных примеров с объяснением. Я не нашел, почему типы объединений разные. В любом случае, я надеюсь, что это поможет. Я попытаюсь воспроизвести то же самое для более поздних версий рельсов.