2

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?

Purrell
  • 12,461
  • 16
  • 58
  • 70

1 Answers1

2

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.

Community
  • 1
  • 1
Jeff Ancel
  • 3,076
  • 3
  • 32
  • 39