I have a model with several layers of nested associations. e.g.,
ModelA has_many: model_b
ModelB has_one : model_c
ModelC has_many: model_d
ModelD has_many: model_e
...
In serializers, embed :ids, include: true
is used for sideloading:
class ModelASerializer < ActiveModel::Serializer
embed :ids, include: true
has_many: model_b
attributes: ...
end
class ModelBSerializer < ActiveModel::Serializer
embed :ids, include: true
...
When model_a is rendered, it has a serious "n+1 problem" and will generate thousands of calls like:
ModelC Load (0.3ms) SELECT "model_cs".* FROM "model_cs" WHERE "model_cs"."id" = $1 LIMIT 1 [["id", "2060c506-8c9c-4d1c-a64c-62455fa18bc4"]]
CACHE (0.0ms) SELECT "model_ds".* FROM "model_ds" WHERE "model_ds"."id" = $1 LIMIT 1 [["id", "2e36f19f-25e1-4953-99ba-f8c0271106dd"]]
CACHE (0.0ms) SELECT "model_es".* FROM "model_es" WHERE "model_es"."id" = $1 LIMIT 1 [["id", "31e53b55-6df6-44cd-98ad-2011cced1e1a"]]
Even if the includes are specified explicitly it doesn't seem to have an effect:
render json: ModelA.includes(:model_bs => [:model_c =>[:model_ds => [:model_es]]])
The active_model_serializers documentation says you should use eager loading but doesn't specify how they intend it to be done. Do the includes have to be specified in the serializer? If so, how?
This is a good description and explanation. This is what you're looking for?
class ModelName
default_scope includes(:other)
end
How to add `:include` to default_scope?
Edit:
I haven't done this in a nest of models like you have, I have done this through one level using serializers, and I've also used jbuilder to ease the pain and leverage control through 2 levels. I still believe you want to put this layer of control on the model level though.
来源:https://stackoverflow.com/questions/23814678/how-to-perform-eager-loading-in-active-model-serializers