Rails:在范围中过滤嵌套属性

时间:2016-12-13 10:45:44

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

我的模型有以下关系:

object TestHelloWorld { def main(args: Array[String]): Unit = { println("hey .. Hello world !!!") } } 有许多Building s,其中Room多个Bed s,

我希望渲染所有Accommodation,但在日期范围内创建Building。从其他答案中我了解到我需要为Accommodation模型创建范围,但我无法理解如何在此范围内过滤此类嵌套属性。

编辑:

假设我有Building 1,2和3.每个Building都有自己的BuildingRoomBed s。可以说只有Accommodation 1有一个Building在范围内。因此返回的数据必须是:

Accommodation

2 个答案:

答案 0 :(得分:2)

避免在模型中编写过度嵌套的连接查询setup indirect relations

class Building
  has_many :rooms
  has_many :beds, though: :rooms
  has_many :accommodations, through: :beds
end

class Room
  belongs_to :building
  has_many :beds
  has_many :accommodations, through: :beds
end

class Bed
  belongs_to :room
  has_many :accommodations
  has_one :building, through: :room
end

class Accommodation
  belongs_to :bed
  has_one :room, through: :bed
  has_one :building, through: :room
end  

这将允许您直接查询building.accommodations,ActiveRecord将为您加入中间表。

然后在查询时使用Range

Building.includes(:accommodations)
        .where(accommodations: { created_at: start_time..end_time })

这将构建一个包含大多数数据库驱动程序的WHERE 'accommodations.created_at' BETWEEN ...

这个难题的另一个关键部分是你没有过滤嵌套属性。相反,上面发生的是您正在使用join and setting conditions on the joined table

答案 1 :(得分:1)

class Building
  scope :accomodations_for_dates, lambda { |start_date, end_date|
    joins(rooms: [beds: :accomodations]).where("accomodations.created_at >= #{start_date} AND accomodations.end_date <= #{end_date}")
  }
end

使用PostgreSQL和MySQL数据库,您可以使用BETWEEN

"accomodations.created_at BETWEEN #{start_date} AND #{end_date}"

要返回所有建筑物,但要使用过滤后的住宿,您需要使用包括:

includes(rooms: [beds: :accomodations]).where(accomodations: { created_at: start_date..end_date })