Я пытаюсь объединить данные из модели 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)
?
Любые мысли или предложения будут оценены.
@ MarcinKołodziej Декораторы были другим подходом, который я использовал для этого. Я действительно мог найти только примеры, в которых они использовались специально для представлений, и эти данные, вероятно, будут использоваться в другом месте приложения, поэтому я не был уверен, был ли это хороший шаблон или нет. Я думаю, что ваша точка зрения о том, что это было более явным, имеет большой смысл.
Хотя я понимаю намерение, стоящее за этим, я бы посоветовал не использовать такой подход, объединение областей видимости действительно не должно иметь побочных эффектов, а выполнение внешних вызовов - неприятное занятие. В этом случае я бы, вероятно, написал декоратор, чтобы обернуть отношение и использовать его очень явно.