日历中的重复事件 - Rails

时间:2012-04-13 22:11:29

标签: ruby-on-rails ruby-on-rails-3 calendar fullcalendar recurring-events

我正在寻找模拟重复活动的最佳方式。我正在使用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

4 个答案:

答案 0 :(得分:40)

以下是我对此进行建模的方法。我没有太多使用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是指创建该事件的员工。 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不够强大,您可能只想在模型中存储Ice cube 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 #唯一标识要更换的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,周期为___seurrence = 2,它应该没有OccurrenceOverride

答案 1 :(得分: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来管理事件计算并将结果存储在事件表中。我首先尝试在没有Occurrence模型的情况下工作,但无论规则引擎多么先进,你总会有例外,因此将事件存储在他们自己的模型中会给你灵活性。

拥有一个Occurrence模型可以更容易地在日历或日期搜索过滤器上显示事件,因为您只需要查询事件,然后显示相关事件的数据,而不是收集给定日期范围内的所有事件然后必须过滤掉时间表不匹配的事件。

此外,您可以将事件发生标记为已取消或修改它(将生成的属性设置为false,以便在编辑ice_cube计划时无法清除它......或者您的业务需要)

当然,如果您的事件无限期重复,您将需要限制未来您希望生成这些事件的距离,并使用自动rake任务清理旧的rake任务并生成下一年的事件或如此。

到目前为止,这种模式对我来说效果很好。

另外,看一下recurring_select gem,它是一个非常整洁的ice_cube表单输入。

答案 2 :(得分:3)

只是一个意见,或许是评论者会指出我目前没有想到的问题:

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

假设每个事件都是由员工创建的(根据您的笔记),然后RecurringEvent也会belong_to :employee。然后,您可以构建has_many :through关系,其中员工有许多事件并且有许多重复发生的事件。

RecurringEvent模型可以有一个开始日期和模式,它最初可以使用此模式来创建各个发生的事件。然后,对于作为周期性系列的一部分的任何事件,您可以修改或删除该个别事件,但您也可以“重新生成系列”,删除系列中的所有事件(或系列中的所有未来事件)并基于此重建它们一种新的模式,例如将会议从“每个星期二”移到“每个星期四”。

关于这一点的另一个好处是你可以创建一个反复出现的事件的一览表,这可能会让你对人们的主要义务有一个很好的洞察力。

就像我说的那样,在我的脑海中,这就是我接近它的方式,但这只是一个想法,我没有建造这样的东西,所以我不知道是否有任何大的陷阱在我建议的方法中。 祝你好运,请发布你最终做的事情!

答案 3 :(得分:-1)

我对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

这对您的解决方案来说听起来合乎逻辑吗? THX