我正在寻找对重复事件进行建模的最佳方法。我正在使用全日历来显示事件。但我想重复发生的事件最好在轨道后端处理。
我已经查看了其他问题和现有的示例代码,但没有找到任何合适的内容。
它的行为应该类似于谷歌日历。因此,应该可以删除/修改重复事件系列的单个事件。但是,将事件系列的所有事件保存在数据库中似乎效率低下。此外,应该可以创建单个事件而不会发生任何重复。
什么是好的模型架构?
我的事件模型现在看起来像这样(没有其他属性):
# Table name: events
#
# id :integer not null, primary key
# employee_id :integer
# created_at :datetime
# updated_at :datetime
# starts_at :datetime
# ends_at :datetime
#
class Event < ActiveRecord::Base
attr_accessible :starts_at, :ends_at
end
这是我对此进行建模的方法。我没有经常使用谷歌日历,所以我的功能基于iCal的重复事件。
所有模型都应具有通常的 id、created_at updated_at属性。列出的是自定义属性。如果该属性是另一个模型,则将通过关联(如 has_one
或 belongs_to
)实现它。
-
RecurrencePeriod
-
Event
base_event #has_one :base_event, :class_name'Event'
-
Time
end_date # 如果永远重复出现,则可能为 nil -
WeeklyRecurrence
重复 #has_one :recurrence, :as=>:recurrence
-
Array[OccurrenceOverride]
覆盖 #has_many :overrides, :class_name=>'OccurrenceOverride'
-
RecurrencePeriod
从其base_event开始的日期开始。此外,我假设Event
的employee_id是指创建该事件的员工。RecurrencePeriod
也将属于创建base_event的员工。
该模型取决于您希望能够指定重复周期的灵活性。您是要支持"每两周一次的星期二和星期四,从上午 10 点到上午 11 点,从下午 2 点到下午 3 点"还是只是"每周重复"?这是一个仅支持"每周重复"、"每两周重复一次"等的模型;如果需要,可以将其展开。
-
WeeklyRecurrence
-
Integer
weeks_between_recurrences -
RecurrencePeriod
recurrence_period #belongs_to :recurrence, :polymorphic=>true
-
我在这里使用多态关联,因为我认为如果您想要多种类型的复发,例如 WeeklyRecurrence
和 DailyRecurrence
,它们可能会很有用。但我不确定它们是否是建模的正确方法,所以如果事实证明它们不是,只需使用has_one :weekly_recurrence
和belongs_to :recurrence_period
。
冰块库似乎对计算重复周期很有用。如果上述WeeklyRecurrence
不够强大,您可能只想在模型中存储冰块Schedule
对象,替换WeeklyRecurrence
。要在模型中存储Schedule
对象,请将其另存为属性"schedule",serialize :schedule
放入模型定义中,然后在数据库中生成文本列"schedule"。
OccurrenceOverride
处理正在编辑的重复事件的单个实例的情况。
-
OccurrenceOverride
-
RecurrencePeriod
recurrence_period_to_override #belongs_to :recurrence_period_to_override, :class_name=>'RecurrencePeriod'
-
Time
original_start_time # 唯一标识要替换的重复周期 -
Event
replacement_event #has_one :replacement_event, :class_name=>'Event'
; 可能为 nil,如果该重复周期被删除而不是编辑
-
不要单独存储事件的每次匹配项,而是在需要在视图中显示它们时临时生成它们。在 RecurrencePeriod
中,创建一个生成Event
的方法generate_events_in_range(start_date, end_date)
,不是保存在数据库中,而只是传递给视图以便它可以显示它们。
当用户编辑重复周期时,他们应该可以选择修改所有匹配项、所有将来发生项或仅修改该事件。如果他们修改所有匹配项,请修改RecurrencePeriod
的base_event。如果他们修改了所有将来出现的情况,请使用应在RecurrencePeriod
上实现的方法,该方法在特定日期的两侧将自身拆分为两个RecurrencePeriod
,然后将更改保存到第二个周期。如果他们仅修改该事件,请为覆盖的时间创建一个OccurrenceOverride
,并将更改保存到替代的replacement_event。
当用户说某个事件现在应该在可预见的未来每两周重复一次时,您应该创建一个新RecurrencePeriod
,并将该事件作为base_event,并且end_date为零。它的重复应该是 weeks_between_recurrence=2 的新WeeklyRecurrence
,并且应该没有OccurrenceOverride
s。
就我而言,我做了这样的事情:
# Holds most of my event's data; name, description, price ...
class Event < ActiveRecord::Base
has_many :schedules
has_many :occurrences
attr_accessible :started_at, :expired_at # expired_at is optional
end
# Holds my schedule object
class Schedule < ActiveRecord::Base
belongs_to :event
attr_accessible :ice_cube_rule # which returns my deserialized ice_cube object
end
# Holds generated or manually created event occurrences
class Occurrence < ActiveRecord::Base
belongs_to :event
attr_accessible :started_at, :expired_at
attr_accessible :generated # helps me tell which occurrences are out of an ice_cube generated serie
attr_accessible :canceled_at
end
从那里,我使用 ice_cube 来管理发生次数计算并将结果存储在发生次数表中。我最初尝试在没有 Occurrence 模型的情况下工作,但无论规则引擎多么先进,您总是会有例外,因此将事件存储在它们自己的模型中可以为您提供灵活性。
使用事件模型可以更轻松地在日历上或使用日期搜索筛选器显示事件,因为您只需要查询事件,然后显示相关事件的数据,而不是收集给定日期范围内的所有事件,然后必须筛选出计划不匹配的事件。
您还可以将事件发生标记为已取消或修改它(将生成的属性设置为 false,以便在编辑ice_cube计划时不会清理它......或任何您的业务需要)
当然,如果您有无限期重复的事件,您将希望限制您希望在多远内生成这些事件,并使用自动 rake 任务来清理旧事件并生成下一年左右的事件。
到目前为止,这种模式对我来说效果很好。
另外,看看recurring_select宝石,这是一个非常整洁ice_cube表单输入。
只是我脑海中的一种意见,也许Comenter会指出一个我目前没有想到的问题:
我会做一个RecurringEvent
模型(或任何你想称呼它的东西)has_many :events
.
假设每个事件都是由员工创建的(基于您的笔记),那么RecurringEvent
也会belong_to :employee
。然后,您可以建立一种has_many :through
关系,其中员工有许多事件并且有许多重复发生的事件。
定期事件模型可以具有开始日期和模式,并且它最初可以使用此模式来创建各个发生的事件。然后,对于属于重复序列的任何事件,您可以修改或删除该单个事件,但您也可以"重新生成序列",删除系列中的所有事件(或系列中的所有未来事件)并根据新模式重建它们,例如将会议从"每个星期二"移动到"每个星期四"。
这样做的另一个好处是,您可以创建一个一目了然的重复事件列表,这可能会让您深入了解人们的主要义务。
就像我说的,这就是我处理它的方式,但这只是一个想法,我没有构建过这样的东西,所以我不知道我建议的方法中是否有任何大的陷阱。
祝你好运,请发布你最终做的事情!
我对Rails很陌生,你的解决方案听起来很有趣。若要创建计划和关联的事件,是否在事件模型中使用条件回调?
就我而言,用户将能够创建事件,无论是否每周重复。所以我在考虑事件模型中的重复布尔字段。所以我想你会有一个第一个回调来创建时间表:
before_save :create_weekly_schedule, if: :recurring
基本上是第二个来创建事件:
after_save :create_occurences_if_recurring
def create_occurences_if_recurring
schedules.each do |sched|
occurences.create(start_date: sched.start_time, end_date: sched.end_time)
end
end
这与您的解决方案合乎逻辑吗?感谢