Class: SerialChronology
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- SerialChronology
- Includes:
- Housekeeping::Timestamps, Housekeeping::Users, Shared::IsData, Shared::SharedAcrossProjects
- Defined in:
- app/models/serial_chronology.rb
Overview
Stores the chronological relationship between two serials.
Direct Known Subclasses
Defined Under Namespace
Classes: SerialMerge, SerialSequence
Instance Attribute Summary collapse
-
#preceding_serial_id ⇒ Integer
The reference/historical serial.
-
#succeeding_serial_id ⇒ Integer
The “new” serial.
-
#type ⇒ String
The type of transition b/w the old and new.
Attributes included from Housekeeping::Users
Instance Method Summary collapse
- #creates_cycle? ⇒ Boolean private
- #depth_first_search(serial, visited) ⇒ Object private
- #no_cycles ⇒ Object private
- #no_self_reference ⇒ Object private
Methods included from Shared::IsData
#errors_excepting, #full_error_messages_excepting, #identical, #is_community?, #is_destroyable?, #is_editable?, #is_in_use?, #is_in_users_projects?, #metamorphosize, #similar
Methods included from Housekeeping::Users
#set_created_by_id, #set_updated_by_id
Methods inherited from ApplicationRecord
Instance Attribute Details
#preceding_serial_id ⇒ Integer
Returns the reference/historical serial.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'app/models/serial_chronology.rb', line 15 class SerialChronology < ApplicationRecord include Housekeeping::Users include Housekeeping::Timestamps include Shared::IsData include Shared::SharedAcrossProjects belongs_to :preceding_serial, class_name: 'Serial', foreign_key: :preceding_serial_id, inverse_of: :preceding_serial_chronologies belongs_to :succeeding_serial, class_name: 'Serial', foreign_key: :succeeding_serial_id, inverse_of: :succeeding_serial_chronologies validates_presence_of :preceding_serial_id, :succeeding_serial_id, :type validates_uniqueness_of :preceding_serial_id, scope: [:succeeding_serial_id] # Scaffolded from GPT 4o 21-5-2025 validate :no_self_reference validate :no_cycles private def no_self_reference if preceding_serial_id == succeeding_serial_id errors.add(:base, "A serial cannot precede or succeed itself") end end def no_cycles if creates_cycle? errors.add(:base, "This link would create a cycle in the chronology") end end def creates_cycle? # We want to see if the `preceding_serial` is reachable from the `succeeding_serial` # If so, adding this link would introduce a cycle visited = Set.new depth_first_search(succeeding_serial, visited).include?(preceding_serial) end def depth_first_search(serial, visited) return visited if visited.include?(serial) visited.add(serial) successors = SerialChronology.where(preceding_serial: serial).includes(:succeeding_serial).map(&:succeeding_serial) successors.each { |succ| depth_first_search(succ, visited) } visited end end |
#succeeding_serial_id ⇒ Integer
Returns the “new” serial.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'app/models/serial_chronology.rb', line 15 class SerialChronology < ApplicationRecord include Housekeeping::Users include Housekeeping::Timestamps include Shared::IsData include Shared::SharedAcrossProjects belongs_to :preceding_serial, class_name: 'Serial', foreign_key: :preceding_serial_id, inverse_of: :preceding_serial_chronologies belongs_to :succeeding_serial, class_name: 'Serial', foreign_key: :succeeding_serial_id, inverse_of: :succeeding_serial_chronologies validates_presence_of :preceding_serial_id, :succeeding_serial_id, :type validates_uniqueness_of :preceding_serial_id, scope: [:succeeding_serial_id] # Scaffolded from GPT 4o 21-5-2025 validate :no_self_reference validate :no_cycles private def no_self_reference if preceding_serial_id == succeeding_serial_id errors.add(:base, "A serial cannot precede or succeed itself") end end def no_cycles if creates_cycle? errors.add(:base, "This link would create a cycle in the chronology") end end def creates_cycle? # We want to see if the `preceding_serial` is reachable from the `succeeding_serial` # If so, adding this link would introduce a cycle visited = Set.new depth_first_search(succeeding_serial, visited).include?(preceding_serial) end def depth_first_search(serial, visited) return visited if visited.include?(serial) visited.add(serial) successors = SerialChronology.where(preceding_serial: serial).includes(:succeeding_serial).map(&:succeeding_serial) successors.each { |succ| depth_first_search(succ, visited) } visited end end |
#type ⇒ String
Returns the type of transition b/w the old and new.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'app/models/serial_chronology.rb', line 15 class SerialChronology < ApplicationRecord include Housekeeping::Users include Housekeeping::Timestamps include Shared::IsData include Shared::SharedAcrossProjects belongs_to :preceding_serial, class_name: 'Serial', foreign_key: :preceding_serial_id, inverse_of: :preceding_serial_chronologies belongs_to :succeeding_serial, class_name: 'Serial', foreign_key: :succeeding_serial_id, inverse_of: :succeeding_serial_chronologies validates_presence_of :preceding_serial_id, :succeeding_serial_id, :type validates_uniqueness_of :preceding_serial_id, scope: [:succeeding_serial_id] # Scaffolded from GPT 4o 21-5-2025 validate :no_self_reference validate :no_cycles private def no_self_reference if preceding_serial_id == succeeding_serial_id errors.add(:base, "A serial cannot precede or succeed itself") end end def no_cycles if creates_cycle? errors.add(:base, "This link would create a cycle in the chronology") end end def creates_cycle? # We want to see if the `preceding_serial` is reachable from the `succeeding_serial` # If so, adding this link would introduce a cycle visited = Set.new depth_first_search(succeeding_serial, visited).include?(preceding_serial) end def depth_first_search(serial, visited) return visited if visited.include?(serial) visited.add(serial) successors = SerialChronology.where(preceding_serial: serial).includes(:succeeding_serial).map(&:succeeding_serial) successors.each { |succ| depth_first_search(succ, visited) } visited end end |
Instance Method Details
#creates_cycle? ⇒ Boolean (private)
45 46 47 48 49 50 |
# File 'app/models/serial_chronology.rb', line 45 def creates_cycle? # We want to see if the `preceding_serial` is reachable from the `succeeding_serial` # If so, adding this link would introduce a cycle visited = Set.new depth_first_search(succeeding_serial, visited).include?(preceding_serial) end |
#depth_first_search(serial, visited) ⇒ Object (private)
52 53 54 55 56 57 58 59 60 |
# File 'app/models/serial_chronology.rb', line 52 def depth_first_search(serial, visited) return visited if visited.include?(serial) visited.add(serial) successors = SerialChronology.where(preceding_serial: serial).includes(:succeeding_serial).map(&:succeeding_serial) successors.each { |succ| depth_first_search(succ, visited) } visited end |
#no_cycles ⇒ Object (private)
39 40 41 42 43 |
# File 'app/models/serial_chronology.rb', line 39 def no_cycles if creates_cycle? errors.add(:base, "This link would create a cycle in the chronology") end end |
#no_self_reference ⇒ Object (private)
33 34 35 36 37 |
# File 'app/models/serial_chronology.rb', line 33 def no_self_reference if preceding_serial_id == succeeding_serial_id errors.add(:base, "A serial cannot precede or succeed itself") end end |