1

好的。所以我有一个 Vehicle 模型和 Schedule 模型。车辆has_many :schedules(时间表belongs_to :vehicle)。时间表具有以下结构:

id | (date)from_date | (date)to_date | (bool)available | (int)vehicle_id

用户指定天数范围:from_date并且to_date我需要退回所有可用天数的车辆

示例(为简单起见,只有一辆车):

[
  (id: 1, from_date: "10/10/2012", to_date: "13/10/2012, available: true, vehicle_id: 1),
  (id: 2, from_date: "14/10/2012", to_date: "15/10/2012", available: true, vehicle_id: 1),
  (id: 3, from_date: "16/10/2012", to_date: "20/10/2012", available: false, vehicle_id: 1)
]

- 测试查询:

1) from_date: "12/10/2012", to_date: "15/10/2012", => 结果:车辆

2) from_date: "11/10/2012", to_date: "17/10/2012", => result: [] (因为 16.10 和 17.10不可用)

3) from_date: "01/11/2012", to_date: "30/11/2012", => 结果:车辆(如果日期范围内没有一天在日程表列表中 - 车辆仍然返回(认为可用)。所以唯一的例外 - 如果范围内的任何一天恰好不是可用的 - 车辆应该被拒绝)

如何实现?对不起,如果它太复杂了。

4

3 回答 3

4

这是使用范围的一种简单方法:

# schedule.rb

scope :unavailable, where(available: false)

def self.between(from_date, to_date)
  where "from_date <= ? AND to_date >= ?", to_date, from_date
end


# vehicle.rb

def self.available_between(from_date, to_date)
  id_not_in Schedule.unavailable.between(from_date, to_date).map(&:vehicle_id)   
end

def self.id_not_in(ids)
  return all if ids.empty?
  where "id NOT IN (?)", ids
end

然后你可以打电话Vehicle.available_between "2012-10-12", "2012-10-15"

这取决于两个观察结果:

  • 可用的时间表无关紧要。只需找到标记为不可用的时间表,然后找到与这些时间表无关的所有车辆。

  • 您可以通过检查以下是否为真来测试两个日期范围 A 和 B 是否重叠

    • A的开始日期在B的结束日期之前
    • A 的结束日期在 B 的开始日期之后

注意我在范围内使用了 Ruby 1.9 语法unavailable,如果您使用的是 1.8,则需要更改available: false:available => false.

于 2012-10-10T12:14:46.227 回答
1
# for each vehicle find all the rows where vehicle is available for given dates
available_schedules = Schedule.where("vehicle_id = ? and from_date <= ? and to_date >= ? and available = ?",vehicle_id,from_date,to_date,true)

# start by assuming that schedule hasn't been found
schedule_found = false

# for each date in you range check all the available schedules if there is one matching your date. 
# If you find a single schedule set schedule_found flag to true and break from loop else loop through all the available schedules.
# Now if schedule_found is true then make it false (to be used by next date) else return [] as per your requirement.  
(from_date..to_date).each do |dt|
    available_schedules.each do |schedule|
            if schedule.from_date <= dt and schedule.to_date >= dt
                    schedule_found = true
                    break
            end
    end

    if schedule_found
            schedule_found = false
    else
            return []
    end
end

# If your code manages to reach here then it means all the dates in range have an available schedule, so just return Vehicle object
return Vehicle.find(vehicle_id)
于 2012-10-10T11:41:14.937 回答
0

尝试找到一个不满足超出可用性范围的条件的时间表组..如果你找不到一个..那是你的赢家

警告:未经测试

v = Vehicle.join(:schedules).where('vehicles.id not in (select vehicle_id from schedules where schedules.from_date > :date and schedules.to_date < :date)', :date => date)

于 2012-10-10T12:07:29.490 回答