通过多个关联模型进行单个ActiveRecord查询

Rom*_*man 2 ruby activerecord ruby-on-rails

我有以下模型和协会:

class Organization
  has_many :buildings
end
class Building
  has_many :counters
end
class Counter
  has_many :counter_records
end
class CounterRecord
  belongs_to :counter
end
Run Code Online (Sandbox Code Playgroud)

我想得到这样的东西

organization.counter_records(dimension_day: start_date...end_date)
Run Code Online (Sandbox Code Playgroud)

([dimension_day: start_date...end_date]- 这是条件).

如何organization通过所有这些模型获得计数器记录?

And*_*eko 5

查看Activerecord查询指南.

特别是你对以下内容感兴趣joins:

Organization.joins(buildings: { counters: :counter_records })
            .where(counter_records: { dimension_day: start_date...end_date })
            .group('organizations.id')
Run Code Online (Sandbox Code Playgroud)

您可以创建一个方法:

class Organization
  def filter_counter_records(start_date, end_date)
    self.class
        .where(id: id)
        .joins(buildings: { counters: :counter_records })
        .where(counter_records: { dimension_day: start_date...end_date })
        .group('organizations.id')
  end
end
Run Code Online (Sandbox Code Playgroud)

现在可以:

organization = Organization.first
organization.filter_counter_records(start_date, end_date)
Run Code Online (Sandbox Code Playgroud)

但更惯用/传统的选择是使用关联:

class Organization
  has_many :buildings
  has_many :counters,        through: :buildings
  has_many :counter_records, through: :counters
end
Run Code Online (Sandbox Code Playgroud)

现在你可以去

organization = Organization.first
organization.counter_records.where(dimension_day: start_date..end_date)
Run Code Online (Sandbox Code Playgroud)

这里的最后一步将建立scopeCounterRecord:

class CounterRecord
  scope :by_date_range, ->(start_date, end_date) { where(dimension_day: start_date..end_date) }
end
Run Code Online (Sandbox Code Playgroud)

现在

organization = Organization.first
organization.counter_records.by_date_range(start_date, end_date)
Run Code Online (Sandbox Code Playgroud)