主动加载与活动记录模型相关联的外部数据

时间:2018-10-30 23:57:57

标签: ruby-on-rails ruby activerecord rails-activerecord

我正在尝试将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)一起使用?

任何想法或建议将不胜感激。

0 个答案:

没有答案