1

わかった。だから私は車両モデルとスケジュールモデルを持っています. 車両has_many :schedules(スケジュールbelongs_to :vehicle)。スケジュールの構造は次のとおりです。

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

ユーザーは日数範囲を指定します:from_dateそしてto_date、すべての日数が利用可能な車両を返す必要があります

例 (簡単にするために 1 台の車両を使用):

[
  (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", => 結果: [] (16.10 と 17.10 が利用できないため)

3) from_date: "01/11/2012", to_date: "30/11/2012", => 結果: 車両 (日付範囲の 1 日もスケジュール リストにない場合 - 車両は引き続き返却されます (利用可能と見なされます)。したがって、唯一の例外 - 範囲のいずれかの日がnot_availableである場合- 車両拒否する必要があります)

これはどのように達成できますか?複雑すぎてすみません。

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"

これは、次の 2 つの観察結果に依存しています。

  • 利用可能なスケジュールは関係ありません。利用不可とマークされたスケジュールを見つけて、それらのスケジュールに関連しないすべての車両を見つけます。

  • 次の両方が当てはまることを確認することで、2 つの日付範囲 A と B が重複しているかどうかをテストできます。

    • A の開始日は B の終了日より前です
    • A の終了日は B の開始日より後です

NBunavailableスコープで Ruby 1.9 構文を使用しました。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 に答える