Class: Event
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Event
- Defined in:
- app/models/event.rb
Overview
== Schema Information
Table name: events
Database name: primary
id :integer not null, primary key
all_day :boolean default(FALSE), not null
description :string
end_time :datetime
event_type :enum
name :string
start_time :datetime
time_zone :string default("America/Chicago"), not null
created_at :datetime not null
updated_at :datetime not null
creator_id :integer
resource_id :integer
CRM marketing/PR event tracked on the calendar.
Has a date + start/end times interpreted in time_zone (default
"America/Chicago"). One or more authors are assigned via the
event_authors join table; creator_id is the audit record of who
first added the event and is set automatically from the current user.
Constant Summary collapse
- DEFAULT_TIME_ZONE =
'America/Chicago'- TIME_ZONE_OPTIONS =
US-focused dropdown for the form, ordered west→east.
[ ['Hawaii (HST)', 'Pacific/Honolulu'], ['Alaska (AKST/AKDT)', 'America/Anchorage'], ['Pacific (PST/PDT)', 'America/Los_Angeles'], ['Mountain (MST/MDT)', 'America/Denver'], ['Arizona (MST)', 'America/Phoenix'], ['Central (CST/CDT)', 'America/Chicago'], ['Eastern (EST/EDT)', 'America/New_York'] ].freeze
Constants included from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
-
#confirm_conflict ⇒ Object
Set to '1' (string) on form submit to bypass the double-booking guard for this save.
-
#end_date ⇒ Object
End date for multi-day events.
- #end_time_of_day ⇒ Object
-
#event_date ⇒ Object
─── Virtual form inputs (start/end dates + wall-clock times) ────────── The form lets the user pick a start date, an optional end date (for multi-day events), and — unless the event is all-day — two wall-clock times, all interpreted in
time_zone. - #event_type ⇒ Object readonly
-
#excluded_conflict_event_id ⇒ Object
Edit_mode in
Crm::EventsController#createdestroys the previous Event and creates a fresh one. - #name ⇒ Object readonly
- #start_time_of_day ⇒ Object
- #time_zone ⇒ Object readonly
Has many collapse
-
#authors ⇒ ActiveRecord::Relation<Author>
validate: false— Rails would otherwise run each Employee's own validations whenever Event#valid? is called, which inherits any preexisting data debt on legacy Employee/Party records (e.g. missing employee_record rows) and surfaces as a phantom "Authors is invalid" error on the Event. - #event_authors ⇒ ActiveRecord::Relation<EventAuthor>
Instance Method Summary collapse
-
#author_conflicts ⇒ Object
Conflicting events for the current author set, excluding self.
- #calendar_end ⇒ Object
-
#calendar_start ⇒ Object
─── FullCalendar serialization ──────────────────────────────────────── All-day events use bare dates; FullCalendar treats the
enddate as EXCLUSIVE, so we emit the day after the (inclusive) end date. - #effective_time_zone ⇒ Object
- #has_author_conflict? ⇒ Boolean
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#confirm_conflict ⇒ Object
Set to '1' (string) on form submit to bypass the double-booking guard for
this save. Used by the "Save anyway" button surfaced after a conflict.
63 64 65 |
# File 'app/models/event.rb', line 63 def confirm_conflict @confirm_conflict end |
#end_date ⇒ Object
End date for multi-day events. Defaults to the start date when blank, so a
single-day event only needs event_date.
95 96 97 |
# File 'app/models/event.rb', line 95 def end_date @end_date || end_time&.in_time_zone(effective_time_zone)&.to_date&.iso8601 end |
#end_time_of_day ⇒ Object
105 106 107 |
# File 'app/models/event.rb', line 105 def end_time_of_day @end_time_of_day || end_time&.in_time_zone(effective_time_zone)&.strftime('%H:%M') end |
#event_date ⇒ Object
─── Virtual form inputs (start/end dates + wall-clock times) ──────────
The form lets the user pick a start date, an optional end date (for
multi-day events), and — unless the event is all-day — two wall-clock
times, all interpreted in time_zone. Combined into UTC start/end
timestamps in assemble_times_from_local_inputs so the DB is
timezone-agnostic. All-day events store start-of-day → end-of-day.
89 90 91 |
# File 'app/models/event.rb', line 89 def event_date @event_date || start_time&.in_time_zone(effective_time_zone)&.to_date&.iso8601 end |
#event_type ⇒ Object (readonly)
72 |
# File 'app/models/event.rb', line 72 validates :event_type, presence: true |
#excluded_conflict_event_id ⇒ Object
Edit_mode in Crm::EventsController#create destroys the previous Event and
creates a fresh one. Without this hint, the new (unsaved) Event sees its
own predecessor as a conflict and 422s the Update. Set this to the soon-
to-be-destroyed Event's id so the double-booking check skips it.
69 70 71 |
# File 'app/models/event.rb', line 69 def excluded_conflict_event_id @excluded_conflict_event_id end |
#name ⇒ Object (readonly)
71 |
# File 'app/models/event.rb', line 71 validates :name, presence: true |
#start_time_of_day ⇒ Object
101 102 103 |
# File 'app/models/event.rb', line 101 def start_time_of_day @start_time_of_day || start_time&.in_time_zone(effective_time_zone)&.strftime('%H:%M') end |
#time_zone ⇒ Object (readonly)
73 74 |
# File 'app/models/event.rb', line 73 validates :time_zone, presence: true, inclusion: { in: ->(_) { TIME_ZONE_OPTIONS.map(&:last) + [DEFAULT_TIME_ZONE] } } |
Instance Method Details
#author_conflicts ⇒ Object
Conflicting events for the current author set, excluding self. Two events
conflict when their [start, end) intervals overlap for the same employee.
133 134 135 136 137 138 139 140 141 142 143 |
# File 'app/models/event.rb', line 133 def return Event.none if start_time.blank? || end_time.blank? || .compact_blank.blank? excluded_ids = [id, excluded_conflict_event_id].compact_blank scope = Event.all scope = scope.where.not(id: excluded_ids) if excluded_ids.any? scope.where('events.start_time < ? AND events.end_time > ?', end_time, start_time) .joins(:event_authors) .where(event_authors: { employee_id: }) .distinct end |
#authors ⇒ ActiveRecord::Relation<Author>
validate: false — Rails would otherwise run each Employee's own
validations whenever Event#valid? is called, which inherits any preexisting
data debt on legacy Employee/Party records (e.g. missing employee_record
rows) and surfaces as a phantom "Authors is invalid" error on the Event.
59 |
# File 'app/models/event.rb', line 59 has_many :authors, through: :event_authors, source: :employee, validate: false |
#calendar_end ⇒ Object
124 125 126 127 128 129 |
# File 'app/models/event.rb', line 124 def calendar_end return if end_time.blank? local = end_time.in_time_zone(effective_time_zone) all_day? ? (local.to_date + 1).iso8601 : local.strftime('%Y-%m-%dT%H:%M:%S') end |
#calendar_start ⇒ Object
─── FullCalendar serialization ────────────────────────────────────────
All-day events use bare dates; FullCalendar treats the end date as
EXCLUSIVE, so we emit the day after the (inclusive) end date.
117 118 119 120 121 122 |
# File 'app/models/event.rb', line 117 def calendar_start return if start_time.blank? local = start_time.in_time_zone(effective_time_zone) all_day? ? local.to_date.iso8601 : local.strftime('%Y-%m-%dT%H:%M:%S') end |
#effective_time_zone ⇒ Object
109 110 111 |
# File 'app/models/event.rb', line 109 def effective_time_zone time_zone.presence || DEFAULT_TIME_ZONE end |
#event_authors ⇒ ActiveRecord::Relation<EventAuthor>
54 |
# File 'app/models/event.rb', line 54 has_many :event_authors, dependent: :destroy, inverse_of: :event |
#has_author_conflict? ⇒ Boolean
145 146 147 |
# File 'app/models/event.rb', line 145 def @has_author_conflict == true end |