Offer
的数量为places
。这意味着每天places
可以为此优惠预订。 Offer
has_many
次预订。
Booking
有一个date_begin
,一个date_end
和belongs_to
一个Offer
。这意味着在date_begin
和date_end
之间的每一天都会使用一个关于相关Offer
的地方。
如果要求预订优惠,我该如何检查是否可以验证?
示例:
- offer has 2 places (offer.places == 2).
- offer has currently 3 bookings (offer.bookings.count == 3)
- First booking B1 is between 01-04-2016 and 10-04-2016
- Second booking B2 is between 01-04-2016 and 05-04-2016
- Third booking B3 is between 08-04-2016 and 10-04-2016.
offer.available_between?("01-04-2016", "10-04-2016")
=> false (because of B1 and B2, and because of B1 and B3)
offer.available_between?("01-04-2016", "05-04-2016")
=> false (because of B1 and B2)
offer.available_between?("08-04-2016", "10-04-2016")
=> false (because of B1 and B3)
offer.available_between?("06-04-2016", "07-04-2016")
=> true (because there is only B1 during this period)
这是一个尝试:
class Offer < ActiveRecord::Base
# True if and only if each day between date_begin and date_end has at least one place left.
def available_between?(date_begin, date_end)
(date_begin.to_datetime.to_i .. date_end.to_datetime.to_i).step(1.day) do |date|
day = Time.at(date)
nb_places_taken_this_day = self.bookings.where("date_begin <= :date AND date_end >= :date", date: day).count
return false if nb_places_taken_this_day >= self.places
end
true
end
end
offer.available_between?(booking.date_begin, booking.date_end)
我对这一点感到不舒服,特别是因为有多个独立的SQL查询。
您能否更有效地使用ActiveRecord看到更好的方法来实现这一目标?
答案 0 :(得分:1)
我没有足够的数据来完整地测试这一点,但我认为这样的事情可以起作用。在这里,我建立了一个条件,即不存在预订,其中开始日期和结束日期不是在请求日期之前或之后。也就是说,确实存在的每个预订最好在请求的开始之前开始和结束,或者在请求结束之后开始和结束。如果预订不符合此条件,则所请求的日期不能作为单个预订提供。这有用吗?
[编辑 - 从原来的破解答案修改以反映实际问题]
这个新的答案仍然会持续几天,但是在一个查询中抓住所有冲突的预订之后这样做了。红宝石循环本身会非常快。
(注意:all?方法将立即在第一个false值上返回false,如果所有元素的值都为true,则返回true,因此我认为编辑所建议的添加return false unless
是多余的。无论如何,我已经在最后一行添加了return
,希望澄清意图。)
def available_between?(date_begin, date_end)
conflicting_bookings = self.bookings.where.not("(date_begin < :requested_start_date AND date_end < :requested_start_date) OR (date_end > :requested_end_date AND date_end > :requested_end_date)", requested_start_date: date_begin, requested_end_date: date_end)
return (date_begin..date_end).all? do |day|
num_bookings_for_day = conflicting_bookings.select{|booking| booking.date_begin <= day && booking.date_end >= day}.count
num_bookings_for_day < self.places
end
end