Итак, у меня проблемы с
Preloading instance dependent scopes are not supported.
У меня три модели
class P < ApplicationRecord
has_many :as
has_many :cs
end
class C < ApplicationRecord
belongs_to :p
end
class A < ApplicationRecord
belongs_to :p
has_one :c, -> (a) { where(feature: a.feature) }, through: :p, source: :cs
end
И у меня есть три сериализатора fast_jsonapi
class PSerializer
include FastJsonapi::ObjectSerializer
has_many :as
end
class CSerializer
include FastJsonapi::ObjectSerializer
belongs_to :p
end
class ASerializer
include FastJsonapi::ObjectSerializer
belongs_to :p
has_one :c
end
И этот один начальный файл
p_model = P.create(title: 'PTitle')
4.times do |i|
A.create(title: "aTitle-#{i}", feature: "feature-#{i}", p: p_model)
C.create(title: "cTitle-#{i}", feature: "feature-#{i}", p: p_model)
end
Я хочу отобразить P с его A и A's C, но когда я пытаюсь сделать
PSerializer.new(P.first, { include: [:as, :'as.c'] }).serialized_json
я получил
P Load (0.1ms) SELECT "ps".* FROM "ps" ORDER BY "ps"."id" ASC LIMIT ? [["LIMIT", 1]]
(0.1ms) SELECT "as"."id" FROM "as" WHERE "as"."p_id" = ? [["p_id", 1]]
A Load (0.1ms) SELECT "as".* FROM "as" WHERE "as"."p_id" = ? [["p_id", 1]]
C Load (0.2ms) SELECT "cs".* FROM "cs" INNER JOIN "ps" ON "cs"."p_id" = "ps"."id" WHERE "ps"."id" = ? AND "cs"."feature" = ? LIMIT ? [["id", 1], ["feature", "feature-0"], ["LIMIT", 1]]
C Load (0.1ms) SELECT "cs".* FROM "cs" INNER JOIN "ps" ON "cs"."p_id" = "ps"."id" WHERE "ps"."id" = ? AND "cs"."feature" = ? LIMIT ? [["id", 1], ["feature", "feature-1"], ["LIMIT", 1]]
C Load (0.1ms) SELECT "cs".* FROM "cs" INNER JOIN "ps" ON "cs"."p_id" = "ps"."id" WHERE "ps"."id" = ? AND "cs"."feature" = ? LIMIT ? [["id", 1], ["feature", "feature-2"], ["LIMIT", 1]]
C Load (0.1ms) SELECT "cs".* FROM "cs" INNER JOIN "ps" ON "cs"."p_id" = "ps"."id" WHERE "ps"."id" = ? AND "cs"."feature" = ? LIMIT ? [["id", 1], ["feature", "feature-3"], ["LIMIT", 1]]
Итак, похоже на N + 1. Но я знаю, что я могу использовать, чтобы решить эту проблему.
PSerializer.new(P.includes({ as: :c }).first, { include: [:as, :'as.c'] }).serialized_json
Упс:
irb(main):010:0> PSerializer.new(P.includes({ as: :c }).first, { include: [:as, :'as.c'] }).serialized_json
P Load (0.1ms) SELECT "ps".* FROM "ps" ORDER BY "ps"."id" ASC LIMIT ? [["LIMIT", 1]]
A Load (0.1ms) SELECT "as".* FROM "as" WHERE "as"."p_id" = ? [["p_id", 1]]
Traceback (most recent call last):
1: from (irb):10
ArgumentError (The association scope 'c' is instance dependent (the scope block takes an argument). Preloading instance dependent scopes is not supported.)
Iможно попробовать с left_joins
irb(main):011:0> PSerializer.new(P.left_joins({ as: :c }).first, { include: [:as, :'as.c'] }).serialized_json
Traceback (most recent call last):
1: from (irb):11
ArgumentError (The association scope 'c' is instance dependent (the scope block takes an argument). Preloading instance dependent scopes is not supported.)
На самом деле то же самое. Как я могу решить эту проблему N + 1?
Я создал рельсовое репо с этими моделями, чтобы вы могли попробовать его самостоятельно. https://github.com/X1ting/reproduce_preload_bug Рельсы 5.2.3 Рубин 2.5.1