Rails игнорирует область объединения при предварительном кэшировании с включенными

TL; DR: У этого вопроса есть свое собственное примерное приложение в https://github.com/skensell/SO-question-example, которое вы можете использовать для отлаживайте себя. Я поставил щедрость уже один раз на этот вопрос, но я не убежден (или не понимаю) аргументы главного ответчика. Я собираюсь поставить еще одну награду за это, потому что это вызывает у меня много разочарований.

ОРИГИНАЛЬНЫЙ ВОПРОС

У меня есть модель User, которая имеет такую ​​ассоциацию:

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

У меня есть конечная точка, которая выполняет поиск пользователей и устанавливает переменную @users, которая будет использоваться представлением. Здесь приходит жуткая часть, которую я нашел в отладчике:

@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, имеет к этому какое-то отношение? Я использую несколько включений и соединений.

UPDATE

Здесь я могу показать вам простой пример этого странного поведения с консоли rails. Кажется, что include..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.

Я могу проверить, что эти запросы относятся к одному и тому же пользователю, и что тот, который помечен Правильный порядок, действительно прав. w.r.t sort_order и created_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.

Ответ 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/ для получения дополнительных примеров с объяснением. Я не нашел, почему типы объединений разные. В любом случае, я надеюсь, что это поможет. Я попытаюсь воспроизвести то же самое для более поздних версий рельсов.

Ответ 2

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

@users.to_a.first.avatars[0..2].map(&:id)
# => [2548, 2546, 2547]
  • Что здесь происходит?

Нет ничего плохого.

В соответствии с Руководство по извлечению одного раздела объекта: 1.1.3 #first

Первый метод находит первую запись, упорядоченную первичным ключом (По умолчанию)

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

И следующие методы, которые возвращаются в виде набора @users.to_a по updated_at

Надеюсь, что это поможет вам!

Ответ 3

Потому что эти вещи разные

# returns a user which has smallest id (@users are ordered by id)
@users.first # User::ActiveRecord_Relation#first

# is different to
# returns a first user which fetched from database (@users are unordered)
@users.to_a.first # Array#first

Ответ 4

IMHO, когда вы предварительно загружаете, информация о заказе в области связей avatars не может использоваться (поскольку возвращаемые "объекты" User, а не Avatar). Из SQL-журнала мы видим, что он просто присоединяет запрос без порядка в avatars.

В случае, если вы не используете .to_a, возвращаемый массив находится в порядке возрастания, так что это был правильный порядок.

Ответ 5

После двух раздач я еще не получил удовлетворительный ответ, поэтому я сделал его просто ошибкой Rails, и я создал проблему в репозитории Rails на Github.

Я размещаю обходной путь здесь, чтобы другие могли решить их проблему с помощью небольшой копии-пасты.

# in user.rb

has_many :avatars, -> { order([:sort_order => :asc,:created_at => :asc])},  dependent: :destroy
def sorted_avatars
  # sometimes the avatars scope is ignored when eagerly loaded with includes
  avatars.to_a.sort do |a1,a2|
    comp = (a1.sort_order <=> a2.sort_order)
    comp.zero? ? (a1.created_at <=> a2.created_at) : comp
  end
end

Я вручу эту вторую награду Александру просто потому, что его комментарий об изменении названия этого вопроса более ценен для меня, чем нынешний самый высокий голос.

Ответ 6

Проблема связана с включением аватаров в ваш запрос. Это приведет к вытаскиванию аватаров в их естественном порядке (id), и область :avatars не будет вызываться, так как каждый пользователь в ответ будет привязан к #avatars.

Я боюсь, что вам придется усилить заказ аватаров при построении вашего запроса:

relation = User.includes(:industries,:avatars)
.where(industries: {id: [1]}).references(:industries)
.order("users.id asc, avatars.sort_order asc, avatars.created_at asc")

avatars = relation.first.avatars

Update

Чтобы проверить побочные эффекты на пользовательском порядке, используйте свой первоначальный тестовый пример и добавьте другого пользователя в ту же отрасль, затем добавьте аватар с помощью sort_order:-1. relation.pluck(:id) вернет [1,1,1,2], поэтому порядок пользователя сохраняется.

Ответ 7

Основное различие между двумя случаями - lazy loading данных с использованием includes.

Случай 1

u = User.first
u.avatars.pluck(:id)
=> [1, 3, 2]

В этом случае запрос sql-запроса

SELECT "avatars"."id" FROM "avatars"  WHERE "avatars"."user_id" = ?  ORDER BY "avatars"."sort_order" ASC, "avatars"."created_at" ASC  [["user_id", 1]]

так как вы не ленив загрузили данные avatar здесь, когда вы пытаетесь получить данные аватара, он попадает в db и использует порядок сортировки, который вы упомянули в этой модели. Как вы можете видеть, order by здесь вы упомянули в своей области.

Случай 2

User.includes(:avatars, :industries).where(industries: {id: [1]}).references(:industries).first.avatars.map(&:id)
=> [1, 2, 3]

В этом случае запрос sql-запроса

SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "users"."created_at" AS t0_r2, "users"."updated_at" AS t0_r3, "avatars"."id" AS t1_r0, "avatars"."user_id" AS t1_r1, "avatars"."sort_order" AS t1_r2, "avatars"."created_at" AS t1_r3, "avatars"."updated_at" AS t1_r4, "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_industries" ON "user_industries"."user_id" = "users"."id" LEFT OUTER JOIN "industries" ON "industries"."id" = "user_industries"."industry_id" WHERE "industries"."id" IN (1) AND "users"."id" IN (1)  ORDER BY "users"."id" ASC

Как вы использовали includes в вышеуказанном запросе, это ленивая загрузка аватаров и industires. Тем не менее, он не использует порядок сортировки, упомянутый вами в модели аватара, при ленивой загрузке данных, поэтому MySql по умолчанию выполняет id как порядок сортировки, который дает (1,2,3)

В этом случае, поскольку данные аватара уже были загружены с леними, при запуске first.avatars он снова не ударил БД, чтобы извлечь данные avatar и просто распечатать данные с ленивых загружаемых значений, которые [1,2,3]