Повторяющиеся события в календаре - Rails
Я ищу лучший способ моделирования повторяющихся событий. Я использую fullcalendar для отображения событий. Но я думаю, что повторяющиеся события лучше всего обрабатывать на бэкэнде рельсов.
Я уже рассмотрел другие вопросы и существующий пример кода, но я не нашел ничего подходящего.
Он должен вести себя аналогично Google Calendar. Поэтому должно быть возможно удалить/изменить отдельные события повторяющихся серий событий. Но сохранение всех событий серии событий в базе данных кажется неэффективным. Также должно быть возможно создать отдельные события без каких-либо повторений.
Что было бы хорошей модельной архитектурой?
Моя модель событий теперь выглядит так (без дополнительных атрибутов):
# 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
Ответы
Ответ 1
Вот как я смогу это моделировать. Я не использовал Календар Google много, поэтому я основываю функциональность от 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 относится к сотруднику, который создал это событие. A RecurrencePeriod
также будет принадлежать сотруднику, который создал base_event.
Модель зависит от того, насколько гибко вы хотите указать повторяемость. Будете ли вы поддерживать "вторник и четверг каждые две недели с 10:00 до 11:00 и с 14:00 до 15:00" или просто "повторяется еженедельно"? Здесь модель, которая поддерживает только "повторяется еженедельно", "повторяется каждые две недели" и т.д.; вы можете расширить его, если вам нужно.
-
WeeklyRecurrence
-
Integer
weeks_between_recurrences
-
RecurrencePeriod
recurrence_period # belongs_to :recurrence, :polymorphic=>true
Я использую полиморфные ассоциации здесь, потому что я думаю, что они могут быть полезны, если вы хотите больше одного типа повторения, таких как WeeklyRecurrence
и DailyRecurrence
. Но я не уверен, что это правильный способ моделирования, поэтому, если они не окажутся, просто используйте has_one :weekly_recurrence
и belongs_to :recurrence_period
.
Библиотека Ice cube кажется, что она может быть полезна для вычисления повторений. Если WeeklyRecurrence
выше недостаточно мощно, вы можете просто захотеть сохранить объект Ice cube Schedule
в модели, заменив WeeklyRecurrence
. Чтобы сохранить объект Schedule
в модели, сохраните его как атрибут "расписание", поместите serialize :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'
; может быть nil, если это повторение было удалено вместо отредактированного
Вместо того, чтобы хранить каждое событие события индивидуально, создавайте их временно, когда вам нужно показать их в представлении. В RecurrencePeriod
создайте метод generate_events_in_range(start_date, end_date)
, который генерирует Event
s, а не сохраняет в базе данных, а просто для перехода к представлению, чтобы он мог их показать.
Когда пользователь редактирует повторение, они должны иметь возможность изменять все вхождения, все будущие вхождения или просто это событие. Если они изменяют все вхождения, измените RecurrencePeriod
base_event. Если они изменяют все будущие вхождения, используйте метод, который вы должны реализовать на RecurrencePeriod
, который разбивается на две RecurrencePeriod
по обе стороны от определенной даты, а затем сохраняет изменения только во второй период. Если они изменяют только это событие, создайте OccurrenceOverride
за время, когда они переопределяют, и сохраните изменения в переопределении replace_event.
Когда пользователь говорит, что определенное событие должно повторяться каждые две недели в обозримом будущем, вы должны создать новый RecurrencePeriod
с этим событием как base_event и nil end_date. Его повторение должно быть новым WeeklyRecurrence
с weeks_between_recurrence = 2, и оно не должно иметь OccurrenceOverride
s.
Ответ 2
В моем случае я сделал что-то вроде этого:
# Holds most of my event 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... или независимо от потребностей вашего бизнеса)
Конечно, если у вас есть события, которые повторяются на неопределенный срок, вы хотите ограничить, как далеко в будущем вы хотите, чтобы эти события были сгенерированы, и использовать автоматические задачи рейка для очистки старых и создания случаев на следующий год или поэтому.
Пока эта модель работает очень хорошо для меня.
Кроме того, посмотрите на recurring_select, который является довольно аккуратным вводом формы ice_cube.
Ответ 3
Просто мнение от моей головы, возможно, коммантеры укажут на проблему, о которой я сейчас не думаю:
Я бы сделал модель RecurringEvent
(или все, что вы хотите назвать), что has_many :events
.
Предположим, что каждое событие создается сотрудником (на основе ваших заметок), тогда RecurringEvent
также будет belong_to :employee
. Затем вы могли бы построить связь has_many :through
, где у сотрудника много событий и много повторяющихся событий.
Модель RecurringEvent может иметь дату начала и шаблон, и первоначально она могла бы использовать этот шаблон для создания отдельных событий. Затем на любом событии, которое является частью повторяющейся серии, вы можете изменить или удалить это отдельное событие, но вы также можете "восстановить серию", удалив все события из серии (или все будущие события в серии) и перестроя их на основе новый шаблон, поэтому, например, переместите встречу с "каждый вторник" на "каждый четверг".
Еще одна приятная вещь об этом - вы можете создать обзорный список повторяющихся событий, что может дать вам некоторое представление о важных обязательствах людей.
Как я уже сказал, с моей точки зрения, что я подхожу к нему, но это всего лишь идея, и я не создал ничего подобного, поэтому я не знаю, есть ли какие-то большие проблемы в подходе Я предлагаю.
Удачи, пожалуйста, напишите, что вы в итоге делаете!
Ответ 4
Я совершенно новый для 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
Является ли это логичным с вашим решением?
спасибо