25

我正在寻找模拟周期性事件的最佳方法。我正在使用fullcalendar来显示事件。但我猜想重复发生的事件最好在rails后端处理。日历中的周期性事件 - 导轨

我已经看过其他问题和现有的示例代码,但我没有找到任何适合的东西。

它应该表现得像谷歌日历类似。所以应该有可能删除/修改循环事件系列的单个事件。但是将事件序列的所有事件保存在数据库中似乎效率不高。也应该可以创建单个事件而不会重复发生。

什么是一个好的模型架构?

我的事件模型,现在看起来像(没有附加属性):

# 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 

回答

37

下面是我将如何建模。我还没有使用Google日历,所以我将基于iCal的经常性事件的功能。

所有模型应该具有通常的id,created_at,updated_at属性。列出的是自定义属性。如果该财产是另一个模型,您将执行它的关联,如has_onebelongs_to

  • RecurrencePeriod
    • Event base_event has_one :base_event, :class_name'Event'
    • Time END_DATE #可以是零,当它反复永远
    • WeeklyRecurrence复发has_one :recurrence, :as=>:recurrence
    • Array[OccurrenceOverride]所覆盖has_many :overrides, :class_name=>'OccurrenceOverride'

RecurrencePeriod开始在其base_event开始的日期。另外,我假定Event的employee_id是指创建该事件的员工。 A RecurrencePeriod也将属于创建base_event的员工。

该模型取决于您希望如何灵活指定重复。您是否打算支持“周二和周四每两周从早上10点到上午11点,从下午2点到下午3点”或者“每周重复”?这是一个支持“每周重复”,“每两周重复一次”的模型。如果需要,您可以扩展它。

  • WeeklyRecurrence
    • Integer weeks_between_recurrences
    • RecurrencePeriod RECURRENCE_PERIOD belongs_to :recurrence, :polymorphic=>true

我用polymorphic associations这里,因为我觉得他们可能是有用的,如果你想要更多的不是一个类型的复发,例如WeeklyRecurrenceDailyRecurrence。但我不确定他们是否是正确的模拟方式,所以如果他们不成立,只需使用has_one :weekly_recurrencebelongs_to :recurrence_period

Ice cube库似乎可能对计算重现有用。如果上面的WeeklyRecurrence功能不够强大,您可能只想在模型中存储冰块Schedule对象,替换WeeklyRecurrence。要将Schedule对象存储在模型中,请将其保存为属性“计划”,将serialize :schedule放入模型定义中,并在数据库中生成文本列“计划”。

OccurrenceOverride处理正在编辑的重复事件的单个实例的情况。

  • OccurrenceOverride
    • RecurrencePeriod recurrence_period_to_override belongs_to :recurrence_period_to_override, :class_name=>'RecurrencePeriod'
    • Timeoriginal_start_time#唯一地识别哪个那RecurrencePeriod内复发取代
    • Event replacement_event has_one :replacement_event, :class_name=>'Event'#;可能是零,如果复发被删除,而不是编辑

而是单独存储事件的每次出现的,暂时生成它们,当你需要向他们展示在视图中。在RecurrencePeriod中,创建一个方法generate_events_in_range(start_date, end_date),该方法生成Event,不保存在数据库中,而只是传递给视图以便显示它们。

当用户编辑重现时,他们应该可以选择修改所有出现次数,所有未来出现次数或仅该事件。如果他们修改所有事件,请修改RecurrencePeriod的base_event。如果他们修改所有将来的事件,请使用您应该在RecurrencePeriod上实施的方法,该方法将自己分裂为某个日期的两侧的两个RecurrencePeriod,然后将更改保存到第二个时间段。如果他们仅修改该事件,则在他们覆盖的时间内创建一个OccurrenceOverride,并将更改保存到覆盖的replacement_event。

当用户表示某个事件现在应该每隔两周在可预见的将来重复出现时,您应该创建一个新的RecurrencePeriod,该事件的事件为base_event和nil end_date。它的复发应该是一个新的WeeklyRecurrence,周期为between_recurrence = 2,它应该没有OccurrenceOverrides。

+1

从没有持续发生,但不能通过id访问它的经验的任何问题? (性能,复杂性等) – ted 2013-09-04 15:59:17

+0

@ted好的问题。我从来没有实现过,所以恐怕我不知道是否根据需要产生事件会导致任何问题。我想你可以根据需要为生成的事件设置一个缓存。缓存系统可能会使用这样一个事实,即生成的保存事件在概念上与“OccurrenceOverride”非常相似,尽管不完全相同。 – 2013-09-04 18:31:35

3

只是一个意见了我的头顶,也许comenters会指出一个问题,我没有想到的目前:

我会做一个RecurringEvent模型(或任何你想称之为)has_many :events

假设每个事件由员工创建(基于您的笔记),那么RecurringEvent也将belong_to :employee。然后,您可以建立一个员工有很多事件并且有许多重复事件的关系。

RecurringEvent模型可以有一个开始日期和一个模式,它最初可以使用这个模式来创建单个事件。然后,在任何属于重复系列赛的事件中,您可以修改或删除个人发生的事件,但是您也可以“重新生成系列”,删除系列中的所有事件(或系列中未来的所有事件)并根据一种新的模式,例如将会议从“每个星期二”移到“每个星期四”。

另外一件好事就是你可以创建一个反复发生的事件的一览表,这可能会让你对人们的主要义务有一个很好的认识。

就像我说过的那样,我的头顶就是这样,但这只是一个想法,我还没有建立这样的任何东西,所以我不知道是否有任何大的陷阱在我建议的方法中。

祝你好运,请张贴你最终做的事!

5

在我来说,我做了这样的事情:

# 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管理出现的计算和存储的结果出现表。我第一次尝试在没有发生模型的情况下工作,但无论规则引擎如何先进,您总会遇到异常情况,因此将事件存储在自己的模型中可以提供灵活性。

拥有一个发生模型使得在日历或日期搜索过滤器上显示事件变得容易很多,因为您只需查询发生次数,然后显示相关事件的数据,而不是收集给定日期中的所有事件然后必须过滤出时间表不匹配的事件。

而且可以标志一个事件发生的取消或修改(设置为false时生成的属性,以便编辑ice_cube时间表时,它不会被清理......或任何您的业务需求是)

中当然,如果您的事件无限期地重复发生,您可能希望限制您希望在将来生成多少事件,并使用自动化耙事任务清理旧事件,并在下一年左右生成事件。

到目前为止,这种模式对我来说工作得很好。

此外,看看recurring_select宝石,这是一个非常整洁的ice_cube形式输入。

+2

好帖子。用这种方法好奇你的想法:http://blog.plataformatec.com.br/2010/04/recurring-events看起来与你的相似。 – Bruno 2014-12-24 02:05:08

+0

布鲁诺,你提到的方法是有效的,只要你不需要坚持这些复发的状态或处理异常(即:在下雨的情况下将演唱会代表推到第二天) – Jim 2014-12-24 16:00:54

+0

@Jim你有没有演示应用程序或示例应用程序,我可以搞砸了吗?我喜欢你的解决方案 – Frank004 2015-03-02 14:49:22

-1

我对Rails很新,你的解决方案听起来很有趣。要创建计划和相关事件,您是否在事件模型中使用条件回调?

在我的情况下,用户将能够创建事件,每周重复或不重复。所以我在考虑事件模型中的循环布尔型字段。所以我想你会第一回调创建时间表:

before_save :create_weekly_schedule, if: :recurring 

和基本的第二个创建OCCURENCES:

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 

这听起来逻辑与您的解决方案? Thx

+1

我看到你回复[我的回答](http://stackoverflow.com/a/10266450/578288)。当您回答特定答案时,您应该对该答案发表评论,否则作者将不会收到通知。另外,如果你的问题很长(像这样),不要把它放在原始问题的另一个答案上;在网站上创建一个与您答复的答案链接的新问题。 – 2014-10-02 00:50:37

+0

至于我认为你的解决方案,我看到它的问题。你说'scheduleles.each' - 但是如果时间表只是“每周重复”,那么'each'循环将永远持续下去,因为时间表没有指定结束日期。这就是为什么我没有提前产生所有事件 - 其中有无数的事件。 – 2014-10-02 00:52:30

相关问题