Événements récurrents dans le calendrier-Rails

Je cherche la meilleure façon de modéliser les événements récurrents. J'utilise fullcalendar pour afficher les événements. Mais je suppose que les événements récurrents sont mieux gérés sur le backend rails.

J'ai déjà regardé d'autres questions et un exemple de code existant mais je n'ai rien trouvé qui convienne.

Il devrait se comporter comme Google Agenda. Il devrait donc être possible de supprimer / modifier des événements uniques de la série d'événements récurrents. Mais l'enregistrement de tous les événements de la série la base de données semble inefficace. En outre, il devrait être possible de créer des événements uniques sans aucune récurrence.

Quelle serait une bonne architecture de modèle?

Mon modèle d'événement ressemble maintenant à ceci (sans attributs supplémentaires):

# 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
27
demandé sur Ben 2012-04-14 02:11:28

4 réponses

Voici comment je modéliserais cela. Je n'ai pas beaucoup utilisé Google Agenda, donc je fonde la fonctionnalité sur les événements récurrents de iCal.

Tous les modèles doivent avoir les propriétés id habituelles, created_at, updated_at. Les propriétés personnalisées sont répertoriées. Si la propriété est un autre modèle, vous allez implémenter une association telle que has_one ou belongs_to.

  • RecurrencePeriod
    • Event base_event # has_one :base_event, :class_name'Event'
    • Time end_date # peut être nul, si il revient pour toujours
    • WeeklyRecurrence récidive # has_one :recurrence, :as=>:recurrence
    • Array[OccurrenceOverride] remplace # has_many :overrides, :class_name=>'OccurrenceOverride'

Le RecurrencePeriod commence à la date à laquelle son base_event démarre. En outre, je suppose que l'ID employee_id d'un Event fait référence à l'employé qui a créé cet événement. Un RecurrencePeriod appartiendra également à l'employé qui a créé base_event.

Le modèle dépend de la souplesse avec laquelle vous voulez pouvoir spécifier des récurrences. Allez-vous soutenir "Mardi et jeudi toutes les deux semaines de 10h à 11h et de 14h à 15h "ou simplement" répète chaque semaine"? Voici un modèle qui prend en charge simplement les "répétitions hebdomadaires", les "répétitions toutes les deux semaines", etc.; vous pouvez l'agrandir si besoin est.

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

J'utilise des associations polymorphes ici, car je pense qu'elles pourraient être utiles si vous en voulez plus plus d'un type de récurrence, tels que WeeklyRecurrence et DailyRecurrence. Mais je ne suis pas sûr qu'ils soient la bonne façon de modéliser cela, donc s'ils s'avèrent ne pas l'être, utilisez simplement has_one :weekly_recurrence et belongs_to :recurrence_period à la place.

La bibliothèqueIce cube semble être utile pour calculer les récurrences. Si WeeklyRecurrence ci-dessus n'est pas assez puissant, vous pouvez simplement stocker un objet Ice cube Schedule dans un modèle, en remplaçant WeeklyRecurrence. Pour stocker un objet Schedule dans un modèle, enregistrez-le en tant qu'attribut "schedule", mettez serialize :schedule dans la définition du modèle, et générer une colonne de texte "schedule" dans la base de données.

OccurrenceOverride gère le cas d'une seule instance d'un événement récurrent en cours de modification.

  • OccurrenceOverride
    • RecurrencePeriod recurrence_period_to_override # belongs_to :recurrence_period_to_override, :class_name=>'RecurrencePeriod'
    • Time original_start_time # identifie de manière unique la récurrence dans cette RecurrencePeriod à remplacer
    • Event replacement_event # has_one :replacement_event, :class_name=>'Event'; peut être nul, si cette récurrence a été supprimée au lieu de édité

Au lieu de stocker chaque occurrence d'un événement individuellement, générez-les Temporairement lorsque vous devez les afficher dans la vue. Dans RecurrencePeriod, créez une méthode {[34] } qui génère Event s, pas pour enregistrer dans la base de données, mais juste pour passer à la vue afin qu'elle puisse les afficher.

Lorsqu'un utilisateur modifie une récurrence, il doit avoir la possibilité de modifier toutes les occurrences, toutes les occurrences futures ou simplement cet événement. S'ils modifient toutes les occurrences, modifiez le base_event de RecurrencePeriod. S'ils modifient toutes les occurrences futures, utilisez une méthode que vous devez implémenter sur {[2] } qui se divise en deux RecurrencePeriod de chaque côté d'une certaine date, puis enregistrez les modifications dans la deuxième période. S'ils ne modifient que cet événement, créez un OccurrenceOverride pour le moment où ils remplacent, et enregistrez les modifications dans replacement_event du remplacement.

Quand un utilisateur dit qu'un certain événement devrait maintenant se reproduire toutes les deux semaines dans un avenir prévisible, vous devriez créez un nouveau RecurrencePeriod avec cet événement comme base_event et un end_date nul. Sa récurrence devrait être un nouveau WeeklyRecurrence avec weeks_between_recurrence=2, et il ne devrait pas avoir de OccurrenceOverrideS.

39
répondu Rory O'Kane 2012-04-22 09:31:08

Dans mon cas, j'ai fait quelque chose comme ceci :

# 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

À partir de là, j'ai utilisé ice_cube pour gérer le calcul des occurrences et stocké les résultats dans la table des occurrences. J'ai d'abord essayé de travailler sans le modèle D'Occurrence, mais peu importe l'avancée du moteur de règles, vous aurez toujours des exceptions, donc stocker les occurrences dans leur propre modèle vous donne de la flexibilité.

Ayant un modèle D'Occurrence, il est beaucoup plus facile d'afficher les événements sur un calendrier ou avec la date filtres de recherche que vous avez juste besoin d'interroger les occurrences, puis afficher les données de l'événement associé au lieu de rassembler tous les événements dans une plage de dates donnée, puis d'avoir à filtrer les événements où le calendrier(s) ne correspondent pas.

Vous pouvez également signaler une occurrence d'événement comme annulée ou la modifier (en définissant l'attribut généré sur false afin qu'il ne soit pas nettoyé lors de la modification d'une planification ice_cube... ou quel que soit le besoin de votre entreprise)

Bien sûr, si vous avez des événements qui répétez indéfiniment, vous voudrez limiter jusqu'où dans le futur vous voulez que ces occurrences soient générées et utiliser des tâches de râteau automatisées pour nettoyer les anciennes et générer des occurrences pour l'année prochaine.

Jusqu'à présent, Ce modèle fonctionne plutôt bien pour moi.

Jetez également un oeil à la gemme recurring_select qui est une entrée de formulaire ice_cube assez soignée.

5
répondu Jim 2014-01-30 01:18:00

Juste une opinion du haut de ma tête, peut-être que comenters soulignera un problème auquel je ne pense pas pour le moment:

Je ferais un modèle RecurringEvent (ou ce que vous voulez appeler) que has_many :events.

Disons que chaque événement est créé par un employé (en fonction de vos notes), puis RecurringEvent serait également belong_to :employee. Vous pouvez ensuite créer une relation has_many :through où un employé a de nombreux événements et a de nombreux événements récurrents.

Le modèle RecurringEvent peut avoir une date de début modèle, et il pourrait initialement utiliser ce modèle pour créer les événements individuels se produisant. Ensuite, sur tout événement faisant partie de la série récurrente, vous pouvez modifier ou supprimer cette occurrence individuelle, mais vous pouvez également "régénérer la série", supprimer tous les événements de la série (ou tous les événements futurs de la série) et les reconstruire en fonction d'un nouveau modèle, par exemple déplacer la réunion de "tous les mardis"à" tous les jeudis".

Un autre genre de chose agréable à ce sujet est que vous pourriez créez une liste d'événements récurrents en un coup d'œil, ce qui pourrait vous donner un bon aperçu des principales obligations des gens.

Comme je l'ai dit, c'est comme ça que je l'aborderais, mais c'est juste une idée et je n'ai rien construit comme ça, donc je ne sais pas s'il y a de gros gotchas dans l'approche que je suggère.

Bonne chance, veuillez poster ce que vous finissez par faire!

3
répondu Andrew 2012-04-15 02:59:13

Je suis assez nouveau pour Rails, votre solution semble intéressante. Pour créer la planification et les occurrences associées, utilisez-vous des rappels conditionnels dans le modèle D'événement?

Dans mon cas, les utilisateurs seraient en mesure de créer des événements, hebdomadaires récurrents ou non. Je pensais donc à un champ booléen récurrent dans le modèle d'événement. Donc, je suppose que vous auriez un premier rappel pour créer le planning:

before_save :create_weekly_schedule, if: :recurring

Et fondamentalement un second pour créer les occurrences:

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

Est-ce que cela semble logique avec votre solution? Thx

-1
répondu stefano_cdn 2014-05-16 23:07:57