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
, как-то связано с этим? Я использую несколько включений и объединений.
ОБНОВЛЕНИЕ
Здесь я могу показать вам простой пример этого странного поведения из консоли rails. Кажется, что the 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.
Я могу проверить, что эти запросы относятся к одному и тому же пользователю, и что тот, который помечен как «Правильный порядок», действительно правильный по отношению к sort_order
и created_at
(именно так ассоциация определяет порядок).
ОБНОВЛЕНИЕ 2
Прилагается запрошенный журнал SQL. Я изменил нерелевантные поля на «Пропущено» и заменил 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- пример. Что еще более странно в этом примере приложения, так это то, что to_a
даже не имеет значения. Я получаю неправильный заказ даже с includes... references
.
7 ответов
Включает учитывает порядок родительской таблицы, записи которой будут извлечены, только когда это приведет к запросу соединения. т.е. в приведенном выше случае порядок аватаров будет пропущен, а порядок пользователей будет использоваться, когда запрос включения приводит к объединению. Вы можете добавить область по умолчанию для пользователя и подтвердить.
Если вы по-прежнему хотите, чтобы пользовательские аватары были отсортированы в соответствии с определенным порядком аватаров, вам необходимо заменить включения объединениями. Обратите внимание, что при использовании соединения будут извлечены повторяющиеся пользовательские записи.
Рабочее решение для получения данных должным образом - использовать соединения и включения вместе.
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">]
По сути, у нас есть 2 функции активной загрузки: preload и eager_load. Когда вы используете include, он вызывает либо preload, либо eager_load. предварительная загрузка приводит к 2 запросам (поиск пользователей и поиск аватаров для извлеченных пользователей), где eager_load использует только 1 запрос (запрос соединения). Таким образом, когда включает результаты в запрос соединения (то есть результаты в eager_load), порядок извлекаемых ассоциаций пропускается, поскольку это единственный запрос.
User.includes(:avatars, :industries).where(industries: {id: [1]}).references(:industries)
Приводит к объединению, потому что вы фильтруете пользователей по конкретным отраслям, что само по себе является «сквозной» ассоциацией. 'через' использует соединение. Также помните, что «соединения» приводят к ВНУТРЕННЕМУ СОЕДИНЕНИЮ, тогда как eager_load использует ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ.
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 / для получения дополнительных примеров с пояснениями. Я не нашел, почему типы соединений разные. В любом случае, я надеюсь, что это поможет. Я постараюсь воспроизвести то же самое для более поздних версий рельсов.
@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 # первый
Первый метод находит первую запись, упорядоченную по первичному ключу (по умолчанию)
SELECT * FROM clients ORDER BY clients.id ASC LIMIT 1
И следующие методы, которые возвращаются как коллекция @users.to_a
по updated_at
Надеюсь, это поможет вам!
Потому что это разные вещи
# 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
IMHO, при предварительной загрузке информация о порядке в области отношения ассоциации avatars
не может использоваться (потому что возвращаемые "объекты" - это User
, а не Avatar
). Из журнала SQL мы видим, что это просто запрос соединения без порядка в полях avatars
.
В случае, если вы не используете .to_a
, возвращаемый массив находится в порядке возрастания, так уж случилось, что это правильный порядок.
После двух наград я так и не получил удовлетворительного ответа, поэтому пришел к выводу, что это просто ошибка 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
Я вручу эту вторую награду Александру просто потому, что его комментарий об изменении названия этого вопроса для меня более ценен, чем текущий ответ с наибольшим количеством голосов.
Основное различие между этими двумя случаями - 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
, когда вы пытаетесь получить данные аватара, он попадает в базу данных и использует порядок сортировки, который вы упомянули в модели. Как видите, 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
в запросе выше, загрузка аватаров и предприятий выполняется лениво. Однако он не использует порядок сортировки, который вы указали в модели аватара при ленивой загрузке данных, поэтому MySql по умолчанию имеет значение id
в качестве порядка сортировки, что дает (1,2,3)
В этом случае, поскольку данные аватара уже были загружены с отложенной загрузкой, когда вы запускаете first.avatars
, он не обращается к базе данных снова, чтобы получить данные avatar
, а просто печатает данные из значений с отложенной загрузкой, которые [1,2,3]
Проблема связана с включением аватаров в ваш запрос. Это приведет к извлечению аватаров в их естественном порядке (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
Обновить
Чтобы проверить побочные эффекты на порядок пользователей, используйте свой первоначальный тестовый пример и добавьте еще одного пользователя из той же отрасли, а затем добавьте аватар с sort_order:-1
. relation.pluck(:id)
вернет [1,1,1,2]
, поэтому порядок пользователей сохраняется.
Похожие вопросы
Новые вопросы
ruby-on-rails
Ruby on Rails - это полнофункциональная платформа веб-приложений с открытым исходным кодом, написанная на Ruby. Он следует популярной модели фреймворка MVC и известен своим подходом «соглашение поверх конфигурации» при разработке приложений.