Стремительная загрузка внешних данных, связанных с моделью активной записи - PullRequest
0 голосов
/ 31 октября 2018

Я пытаюсь объединить данные из модели ActiveRecord с внешними данными, связанными с каждым объектом, и я пытаюсь найти чистый и эффективный способ сделать это.

Я, очевидно, могу определить метод экземпляра в модели для извлечения соответствующих внешних данных:

class State < ActiveRecord::Base
  def counties
    @counties ||= fetch_external_data(state: name)['counties']
  end
end

State.find_by_name('Alabama').counties

Но если у меня есть коллекция объектов (через ActiveRecord::Relation), то это приведет к N + 1 запросу к этому внешнему источнику данных.

State.where(name: %w[Alabama Georgia]).map(&:counties)

В идеале, я бы с нетерпением ждал загрузки всех данных из внешнего источника данных, а затем использовал бы метод экземпляра counties для доступа к данным из этого «общего» объекта. Я мог бы сделать это, используя метод класса:

class State < ActiveRecord::Base

  attr_accessor :counties

  def self.with_counties
    # Get external data for all states in our scope
    counties = fetch_external_data(states: pluck(:name))

    # Group by the state
    counties_by_state = counties.group_by { |c| c['state'] }

    # Now hydrate all of the state models and set the counties
    all.map do |state|
      state.counties = counties_by_state.dig(state.name, 'counties')
    end
  end
end

Несмотря на то, что это возможно, я не могу продолжать цепочку прицелов после использования State.where(name: %w[Alabama Georgia]).with_counties, и мне кажется, что с ним можно работать более элегантно.

Существует ли четкий способ «загружать» данные, подобные этой (т. Е. Возможность установить «данные сбора» для объекта ActiveRecord::Relation, к которому можно получить доступ при гидратации записи)? Если у меня есть класс, представляющий этот интерфейс внешних данных, есть ли методы, которые я мог бы определить для этого класса, чтобы он работал с State.includes(:counties) или State.eager_load(:counties)?

Будем благодарны за любые мысли или предложения.

...