вложенный запрос к активному атрибуту сериализатора модели

#ruby-on-rails #performance #activerecord #active-model-serializers

#ruby-on-rails #Производительность #activerecord #active-model-serializers

Вопрос:

У меня есть две модели, обложка и событие, в обложке много событий. Некоторые события подтверждены.

В моем сериализаторе я хочу вернуть последнее подтвержденное событие для каждого произведения искусства

Прямо сейчас это происходит, но также создает медленный (n 1?) запрос, в котором каждое сериализованное изображение извлекает все события.

Как я могу сделать что-то быстрее?

 
# artwork_controller.rb
      def index
        @artworks = Artwork.all
        render json: @artworks
      end

# artwork_serializer.rb
      attributes :id, :name, :photo, :created_at

      has_one :event do
        object.events.confirmed.last
      end
  

и журналы

 Processing by Api::V1::ArtworksController#index as JSON
  Passenger Load (2.0ms)  SELECT "artworks".* FROM "artworks"
  ↳ app/controllers/api/v1/artworks_controller.rb:11
[active_model_serializers]   Event Load (1.2ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 16], ["published", true], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9
[active_model_serializers]   Event Load (0.8ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 9], ["published", true], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9
[active_model_serializers]   Event Load (2.1ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 27], ["published", true], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9#
# ... for each artwork

[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9
[active_model_serializers]   User Load (1.7ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 84], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/event_serializer.rb:9
[active_model_serializers]   CACHE Event Load (0.0ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 9], ["published", true], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9
[active_model_serializers]   User Load (0.6ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 88], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/event_serializer.rb:9
[active_model_serializers]   CACHE Event Load (0.0ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 27], ["published", true], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/artwork_serializer.rb:9
[active_model_serializers]   User Load (0.5ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 76], ["LIMIT", 1]]
[active_model_serializers]   ↳ app/serializers/api/v1/event_serializer.rb:9
[active_model_serializers]   CACHE Event Load (0.0ms)  SELECT  "events".* FROM "events" WHERE "events"."artwork_id" = $1 AND "events"."published" = $2 ORDER BY "events"."created_at" DESC LIMIT $3  [["artwork_id", 11], ["published", true], ["LIMIT", 1]]
# ... for each artwork events
  

Ответ №1:

вы можете попробовать это:

Пожалуйста, добавьте эту ассоциацию в artwork модель.

 # app/models/artwork.rb

has_one :last_confirmed_event, -> { order(created_at: :desc).where(confirmed: true) }, class_name: "Event"
  

В вашем artworks контроллере добавьте быструю загрузку.

 # app/controllers/artwork_controllers.rb

def index 
  @artworks = Artwork.all.includes(:last_confirmed_event)
  render json: @artworks 
end
  

В последнем случае используйте объявленную ассоциацию в вашем сериализаторе.

 # app/serializers/artwork_serializer.rb

attributes :id, :name, :photo, :created_at

has_one :last_confirmed_event
  

Вы можете изменить имя ассоциации по своему выбору.

Комментарии:

1. Почти так же, как он всегда возвращает первое событие, а не последнее, настройка запроса выполняет свою работу has_one :last_ confirmed_event, -> { order(created_at: :desc).where(confirmed: true) }, class_name: 'Event'