两个关键:
- 将活动与其日程分开。
- 将重复计划定义与其单独的计划分开。
通过将事件与其日程表分开,重复事件的实例可以共享相同的事件信息,例如其描述和位置,而其他实例可以使用经过编辑的版本。
events:
id
name
description
location
...
通过将重复计划与其单独的计划分开,查询事件变得更加简单。
recurring_event_schedules:
id
event_id
schedule: jsonb
start_at: timestamp with time zone
这是一个活动的定期安排。
定期安排变得复杂。您可以为每种类型的重复周期(每年、每两年、每天、每月、每周等)创建多个表,或者使用jsonb 来存储规范。每个工作日的规格可能是{ "period": "weekly", "days": [1,2,3,4,5] }。参考 iCal 规范和优秀的日历软件,了解您想要的重复事件类型和其他属性。
jsonb 不是万能的,但此表仅供参考,用于生成和更新事件。它不用于运行时查询。为此,还有第二张桌子。
然后从中生成单独的计划事件,直至可配置的限制。
event_schedules:
id
event_id
recurrent_event_schedule_id
schedule: tztsrange
这张表很简单。它是根据什么事件、时间和重复计划生成的。
由于您使用的是 Postgres,而不是单独的开始/结束字段,因此请使用 timestamp range。 special operators 支持这些,以确定时间是否在范围内,或者范围是否重叠,等等。
Rails will accept Range types,但不直接支持运算符。例如,EventSchedule.where("duration @> ?::date", Date.new(2014, 2, 12)) 查找 2014 年 2 月 12 日发生的所有事件。
如果您要编辑单个已安排的事件,请复制其事件,对其进行编辑,然后将 EventSchedule 链接到该新事件。
如果您想更改周期性活动时间表,请按recurrent_event_schedule_id 选择event_schedules。
如果您想更改所有预定事件的事件,请编辑链接到 RecurringEventSchedule 的事件。
通过这种方式,您可以定义复杂的重复事件并查询简单的具体事件。