14

Tło

Mam aplikację szyn z głęboko zagnieżdżonymi skojarzeniami.Chętne skojarzenia obciążenia z aktywnymi modelami szeregowymi

      .-< WorkPeriod 
Timecard -< Week -< Day -<--< Subtotal 
          `-< Adjustment 

-< (has many) 

Używam Active Model Serializer aby zbudować API.

Po stronie klienta chcę załadować kartę czasową i wszystkie jej powiązania w jednym ujęciu.

Obecnie moje serializers wyglądać tak,

class TimecardSerializer < ActiveModel::Serializer 
    embed :ids, include: true 
    has_many :weeks 
end 
class WeekSerializer < ActiveModel::Serializer 
    embed :ids, include: true 
    has_many :days 
end 
# ... etc ... 

Problem

To wszystko działa znaleźć, chyba nic nie dostaje chętny załadowane. Tak więc kończy się wykonywanie wielu połączeń do bazy danych dla każdego żądania. W każdym tygodniu składa osobny wniosek dotyczący dni w tym tygodniu. I na każdy dzień składa osobną prośbę o jej okresy pracy, podsumy i korekty.

Odpowiedz

9

Jednym z rozwiązań jest zdefiniowanie własnej metody weeks w TimecardSerializer. Stamtąd możesz .includes() wszystkie skojarzenia, które chcesz załadować.

class TimecardSerializer < ActiveModel::Serializer 
    embed :ids, include: true 
    has_many :weeks 

    def weeks 
    object.weeks.includes(days: [:sub_totals, :work_periods, :adjustments]) 
    end 
end 

Wszystkie zapytania będą nadal wyświetlane w dzienniku, ale większość będzie zapytaniem z pamięci podręcznej zamiast prawdziwym.

+1

To jest dobre dla ładowania pojedynczego zasobu, ale nie będzie działać, jeśli ten serializator zostanie użyty do zwrócenia listy 'Karty czasowe'. W szczególności "tygodnie" nie będą chętnie ładowane, chociaż będą to stowarzyszenia "tygodni". – hjdivad

8

Miałem podobny problem. Naprawiłem to w moim kontrolerze. Podoba mi się pomysł umieszczenia go w serializatorze, ale posiadanie go w kontrolerze uwzględnia również problem n + 1-tygodniowy stworzony przez ArraySerializer.

Timecard.find(params[:id]).includes(weeks: [{ days: [:sub_totals, :work_periods, :adjustments] }]) 

i

Timecard.includes(weeks: [{ days: [:sub_totals, :work_periods, :adjustments] }]) 

powinien teraz chętni obciążenia i ograniczyć zapytanie do zaledwie sześć trafień dB.