如何分组,计算和映射日期范围?

时间:2018-02-28 20:48:08

标签: ruby-on-rails json ruby ruby-on-rails-5

我在预订模式上工作,可以在任意时间段内租用物品,每件物品每天最多可以预订(基本上是物品的数量)。显然,我想检查一个项目是否可用于预订,或者是否在预订之前已达到最大容量。我考虑在Booking模型中创建一个方法,该方法返回一个包含所有 un 可用日期和项目的对象数组,以便所需的输出为:

[ {rentalitem_id: 1, unavailable: '01-03-2018'},
  {rentalitem_id: 2, unavailable: '02-03-2018'},
  {rentalitem_id: 1, unavailable: '01-03-2018'} ]

然后,我可以使用JSON渲染方法,以便在我的前端(Vue.js)中访问它,在那里我可以简单地禁用相应项目的所有日期。当然,我还会在处理预订时验证后端是否有日期。

第一个问题:您如何看待这个想法?也许有更优雅的解决方案如何实现这一目标?

到目前为止,我写的预订模型中的方法如下所示:

class Booking < ApplicationRecord

 ...

   scope :future_bookings, -> (time) { where("rental_start >= ?", time) }

 ...

   def self.item_unavailable
      sorted_booking = future_bookings(Time.now).map do |booking|
         { rentalitem_id: booking.rentalitem_id,
           dates: ((booking.rental_start.to_date..booking.rental_end.to_date).map{ |date| date.strftime("%b %d %y") }).to_a }
      end
      merged_bookings = sorted_booking.group_by{ |key| key[:rentalitem_id]}.each do |_, value|
          value.map!{ |arr| arr[:dates] }
      end
   end
end

所以,基本上我会映射所有未来的预订,创建一个由rentalitem_idrental_startrental_end之间的所有日期组成的变量。之后,我按rentalitem_id对这些结果进行分组,以便merged_bookings现在返回预订项目的所有日期:

# { 1=>[["Feb 28 18", "Mar 01 18", "Mar 02 18", "Mar 03 18"], ["Mar 01 18", "Mar 02 18", "Mar 03 18", "Mar 04 18", "Mar 05 18"]], 2=>[["Mar 01 18", "Mar 02 18"], ["Mar 02 18", "Mar 03 18"], ["Mar 02 18", "Mar 03 18", "Mar 04 18"]] }

我们的想法是计算整个数组中的所有相交日期,并在达到相应租赁项目的最大容量时返回日期,而应从rentalitem模型中查询最大容量。然而,我被困在这里并尝试了我能想象到的所有动作。我想过使用inject来返回不可用的值,但在此之前我需要计算相交日期?

假设第一个rentalitem每天最多可以预订两次,而不是3月1日不可用。此外,假设第二rentalitem具有每天三次预订的最大容量。因此,在示例后的3月2日它应该不可用。

我非常感谢这里的一些帮助:-)

2 个答案:

答案 0 :(得分:1)

我创建一个RentalItemAvailability类,传递rental_item和日期,以便检查给定日期的可用性,而不是试图制作一些非常奇怪的东西,弄清楚如何实现一系列日期相同......如:

class RentalItemAvailability
  delegate :maximum_capacity_per_day, :bookins, to: :@rental_item

  def initialize(rental_item, date)
    @rental_item = rental_item
    @date = date
  end

  def available?
    bookings_on_date < maximum_capacity_per_day
  end

  def bookins_on_date
    bookins
     .where('rental_start between :date and :date and rental_end between :date and :date', @date).count
  end
end      

这样您就可以每天验证并将rental_item标记为可用/不可用

答案 1 :(得分:0)

我相信您要求修改item_unavailable以返回每个项目/日期的计数。要做到这一点,你可能想要根据item_id在ruby中构建一个哈希,item_id包含日期和计数。像这样:

{
  1: {
    "Feb 28 18": 1,
    "Mar 01 18": 2
  }
}

另一种方法是为每个日期存储单独的预订(而不是具有开始和结束日期)。这最终将成为更多的记录,但我相信这将是一种更直观的方法。 查询类似于上面哈希的结果的示例:

future_bookings.group(:rentalitem_id, :date).count
# {[1, "date_from_db"]=>2, [2, "date2_from_db"]=>1}