From a7a6ad786eeb9f94f7882462bccbdd31e1bb4743 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Tue, 30 Jun 2026 19:15:22 +0200 Subject: Phase 1: standalone events, external_url on nodes - Migration: node_id nullable on events and occurrences, add title/description/is_primary to events, external_url to nodes - Existing events marked is_primary: true (were all 1:1 with nodes) - Node: has_one :event -> has_many :events - Event: belongs_to :node optional, validates title presence for standalone events, is_primary uniqueness scoped to node_id, display_title helper falling back through node title - Occurrence: belongs_to :node optional, summary falls back to event.display_title - nodes_helper: event_information uses events.first (interim; will be replaced in Phase 3 event UI) - Tests: fix node.event -> node.events.first in event_test --- app/helpers/nodes_helper.rb | 11 ++++++----- app/models/event.rb | 29 ++++++++++++++++------------- app/models/node.rb | 2 +- app/models/occurrence.rb | 9 ++++----- 4 files changed, 27 insertions(+), 24 deletions(-) (limited to 'app') diff --git a/app/helpers/nodes_helper.rb b/app/helpers/nodes_helper.rb index a054a2e..d88d12a 100644 --- a/app/helpers/nodes_helper.rb +++ b/app/helpers/nodes_helper.rb @@ -30,12 +30,13 @@ module NodesHelper end def event_information - if @node.event + if @node.events.first + event = @node.events.first safe_join([ - "#{@node.event.start_time.to_fs(:db)} - #{@node.event.end_time.to_fs(:db)} > ", - link_to('show', event_path(@node.event)), - ' ', - link_to('edit', edit_event_path(@node.event)) + "#{event.start_time.to_fs(:db)} - #{event.end_time.to_fs(:db)} > ", + link_to('show', event_path(event)), + ' > ', + link_to('edit', edit_event_path(event)) ]) else safe_join([ diff --git a/app/models/event.rb b/app/models/event.rb index 94a22e3..26c79e4 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,22 +1,25 @@ class Event < ApplicationRecord - - # Associations - - has_many :occurrences - belongs_to :node - - # Callbacks - - after_save :generate_occurences - - # Instance Methods - + + belongs_to :node, optional: true + has_many :occurrences + + validates :title, presence: true, unless: -> { node_id.present? } + validates :is_primary, uniqueness: { scope: :node_id, + message: "only one primary event per node allowed" }, + if: -> { is_primary? && node_id.present? } + + after_save :generate_occurences + def occurrences_in_range start_time, end_time self.occurrences.where( "start_time > ? AND end_time < ?", start_time, end_time ) - end + end + + def display_title + title.presence || node&.head&.title || "Untitled event" + end private def generate_occurences diff --git a/app/models/node.rb b/app/models/node.rb index 92ecc12..ba94e2a 100644 --- a/app/models/node.rb +++ b/app/models/node.rb @@ -7,7 +7,7 @@ class Node < ApplicationRecord belongs_to :head, :class_name => "Page", :foreign_key => :head_id, :dependent => :destroy, optional: true belongs_to :draft, :class_name => "Page", :foreign_key => :draft_id, :dependent => :destroy, optional: true has_many :permissions, :dependent => :destroy - has_one :event, :dependent => :destroy + has_many :events, :dependent => :destroy belongs_to :lock_owner, :class_name => "User", :foreign_key => :locking_user_id, optional: true # Callbacks diff --git a/app/models/occurrence.rb b/app/models/occurrence.rb index 3baf447..143124f 100644 --- a/app/models/occurrence.rb +++ b/app/models/occurrence.rb @@ -1,13 +1,12 @@ -# TODO Make a gem out of the c wrapper require 'chaos_calendar' class Occurrence < ApplicationRecord # Associations - belongs_to :node + belongs_to :node, optional: true belongs_to :event - + # Class Methods def self.find_in_range start_time, end_time @@ -64,7 +63,7 @@ class Occurrence < ApplicationRecord # Instance Methods def summary - node.head.title + node&.head&.title || event.display_title end - + end -- cgit v1.3