É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
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 OccurrenceOverride
S.
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.
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!
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