在 Rails 中构建预约系统
Posted
技术标签:
【中文标题】在 Rails 中构建预约系统【英文标题】:Building an appointment booking system in Rails 【发布时间】:2015-08-02 04:19:38 【问题描述】:我正在寻找具有以下特点的预约应用程序: - 用户可以是服务提供者或购买者 - 服务提供商设置他们的可用性(但只能将他们的可用性设置为最多提前 6 个月) - 然后,买家可以根据这些可用性进行预约 - 每个预约,根据服务类型,需要不同的时间 - 根据买家选择的预约,根据服务所需的时间显示一组不同的可用性
我构建的内容如下:
- 一个TimeSlot
模型,我基于start_time
和end_time
属性创建了许多通用的30 分钟时间段。为了使这些时间段延长到未来 6 个月,我每天运行一个后台作业,创建所有必要的新时间段
class TimeSlot < ActiveRecord::Base
has_many :user_time_slots
# ... more methods below
end
- 一个UserTimeSlots
模型,基本上代表他们可以设置的服务提供商的可用性。所以当他们创建一个 user_time_slot 时,他们本质上是在说他们当时可用。
class UserTimeSlot < ActiveRecord::Base
belongs_to :time_slot
belongs_to :service_provider, :class_name => "User"
belongs_to :appointment
end
- 一个Appointment
模型,它有很多 user_time_slots。它有很多,因为约会属于需要一定时间的服务(服务上的time_required
属性)并且它可能跨越多个连续 user_time_slots。
class Appointment < ActiveRecord::Base
has_many :user_time_slots
belongs_to :buyer, :class_name => "User"
belongs_to :service_provider, :class_name => "User"
belongs_to :service
end
- 一个Service
模型,它有许多约会并且属于创建该服务的服务提供商。
class Service < ActiveRecord::Base
has_many :appointments
belongs_to :service_provider, :class_name => "User"
end
此领域模型有效;但是,由于以下原因,我想知道是否有更好的方法:
每天使用后台作业在我的后端创建 TimeSlot 记录对我来说似乎有点笨拙 - TimeSlot 的唯一目的是拥有开始和结束时间,然后与之关联。
一旦用户(买方)选择了他们想要的服务,我不确定如何有效地找到 x 个连续的 user_time_slots,因此可用于预约(例如,如果我有 30 分钟时隙间隔和用户选择需要 3 小时的约会,我必须找到 6 个连续的时隙)。例如,如果用户单击服务实例,我将不得不 1) 获得该服务所需的时间(很容易做到)和 2) 我必须找到所有用户的 user_time_slots 并收集他们的关联time_slots,然后将每个时间槽的开始和结束时间相互比较以找到连续的时间。对我来说,这似乎是太多的迭代,这似乎会使我的应用程序陷入困境!有没有人有更好的方法或解决方案来做到这一点(特别是围绕寻找连续时隙的主题)?
【问题讨论】:
您在这里想到什么样的“可信和/或官方来源”? 真的只是在这里寻找一个深思熟虑的解决方案 - 不需要真正的官方资格 【参考方案1】:不要随意分割时间段,特别是如果很少有约会可能恰好是一个 30 分钟的间隔,而是创建具有任意开始和停止时间的约会。假设约会不会跨越几天,您可以拥有一个包含多个约会的 Day 模型。您将必须以编程方式处理重叠计算,但这样做不会将您的数据库打死,您只需要加入 Day、Appointment 和 Providers,然后运行计算以找到您的空缺职位。约会可以是 5 分钟或 6 小时。没关系。
【讨论】:
这是有道理的——但是,服务提供商将如何设置他们的可用性?例如,如果某人从上午 9 点到下午 12 点有空,那么从下午 3 点到下午 6 点(甚至比这更细化)。管理这似乎我需要有一些其他类型的模型与一天相关联? 这就是我会做的。您可以使用其他模型来对约会、日期、可用性等进行分组,例如周、工作周、月、年等。这都是相当严格和随意的,如果您正在查看一个简单的单- 使用应用程序。一个抽象层通过具有_one TimeUseAssociationCategory 的TimeUseAssociation 为您提供具有_many TimeBlocks 的TimeBlock。这是一个循环引用,这让大多数人头疼,所以除非你在寻找通用性,否则我会选择更简单但更严格的模型。 我还想指出,Postgresql 提供范围数据类型,包括日期范围和日期时间戳(有和没有时区),这可能会使您更轻松地处理 TimeBlocks。【参考方案2】:我会为每个可用期提供一个模型。每个时期都有一个start_time
和end_time
。他们可以很容易地验证不超过提前 6 个月,您可以检查约会是否合适。您的时间段不需要属于这样的约会;约会只是有一个时间和一个服务提供商,并且所述服务提供商的可用性将改变以反映预订的约会。
class AvailabilityPeriod < ActiveRecord::Base
belongs_to :service_provider, :class_name => "User"
validates :end_time, :inclusion => :in => Time.now..(Time.now + 6.months)
end
例如,您可以像这样找到给定服务和提供商的所有可能可用性:
duration = @service.duration
available_times = @provider.availability_periods.where (end_time - start_time > duration)
预约有点棘手。您需要拆分/缩短可用期。例如,假设提供者具有以下可用性:
5月30日12:00-18:00
预约时间为 5 月 30 日 14:00 - 16:00
需要删除旧的可用性并用两个新的可用性替换: 5月30日 12:00 - 14:00 5月30日16:00-18:00
但这在模型方法中很容易做到。
【讨论】:
【参考方案3】:我喜欢 jpriebe 的解决方案,但我建议对验证稍作改动:使用 (Date.today + 6.months).end_of_day
作为范围的最末端。
我提出建议的原因是使系统更加用户友好。如果您使用Time.now
,并且用户想要创建一个在下午 4 点结束的 AvailabilityPeriod,但它仍然是凌晨(例如,上午 10:15 左右),那么下午 4 点将超出范围。要创建 AvailabilityPeriod,他们必须记住稍后再回来 - 他们可能会忘记/正在将烤宽面条从烤箱中取出/在此处分散注意力。
诚然,这种情况实际上只有一个可能发生的时间,那就是如果用户试图在 正好 6 个月前创建一个 AvailabilityPeriod(例如,5 月 27 日 => 11 月27)。大多数情况下,我确信大多数用户不会提前那么早设置 AvailabilityPeriod。尽管如此,使用.end_of_day
会将可接受的时间范围延长到适当的一天结束。
【讨论】:
【参考方案4】:看起来像一个有趣的项目。 :)
我个人不会为“现有时间”建模,即我不会让后台作业创建“空”数据。
我会尝试这样的模型:
User 表在哪里?
我不会为两种不同的用户类型使用共享用户模型。我的直觉是,他们需要有所不同,如果不是现在,随着时间的推移会变得非常粗暴。在我看来,它也使模型更加清晰。如果有登录名或任何身份验证,我会为该特定数据添加一个用户表,而不是让 Service Provider 和 Consumer 与此有一些关系。
服务提供商管理可用性
服务提供者只需要一个空日历(或类似的),只列出她已经输入的服务可用性,每个服务。
消费者预约
消费者将搜索/浏览/导航服务可用性,每个服务
取决于业务逻辑,即消费者是否总是安排整个定义的时间段?或者消费者可以预订一个首选的时间段。只要预订的时段在给定服务的可用时段内?
调度
所以我们只在 Service Provider 管理特定Service 的可用性时才放入Service Availability 记录。 Empty 被简单地认为是不可用的。
我们仅在消费者预订服务时放入约会记录,基于服务可用性。
如果消费者可以只预订服务可用性时间段的一部分,我建议创建两个(或一个)新的服务剩余时间的可用性记录。可以通过比较 Service Availability 和 Appointment 来检查时间是否可用,但这不是最佳选择。 更好的办法是只查询特定 Service 的 Service Availability 并获得可用性计划,没有记录就意味着没有可用性。
这里有很多 if,具体取决于您的特定需求和请求的业务逻辑。但我希望这有助于一些灵感和想法。
【讨论】:
以上是关于在 Rails 中构建预约系统的主要内容,如果未能解决你的问题,请参考以下文章