otwarchive-symphonyarchive/app/models/skin_parent.rb

78 lines
2.3 KiB
Ruby
Raw Normal View History

2026-03-11 22:22:11 +00:00
class SkinParent < ApplicationRecord
belongs_to :child_skin, class_name: "Skin", touch: true
belongs_to :parent_skin, class_name: "Skin"
validates :position,
uniqueness: {scope: [:child_skin_id, :parent_skin_id], message: ts("^Position has to be unique for each parent.")},
numericality: {only_integer: true, greater_than: 0}
validates_presence_of :child_skin, :parent_skin
validate :no_site_parent
def no_site_parent
return unless parent_skin&.get_role == "site" && %w[override site].exclude?(child_skin.get_role)
errors.add(:base, :site_parent, title: parent_skin.title)
end
validate :no_circular_skin
def no_circular_skin
if parent_skin == child_skin
errors.add(:base, ts("^You can't make a skin its own parent"))
end
parent_ids = SkinParent.get_all_parent_ids(self.child_skin_id)
if parent_ids.include?(self.parent_skin_id)
errors.add(:base, ts("^%{parent_title} is already a parent of %{child_title}", child_title: child_skin.title, parent_title: parent_skin.title))
end
child_ids = SkinParent.get_all_child_ids(self.child_skin_id)
if child_ids.include?(self.parent_skin_id)
errors.add(:base, ts("^%{parent_title} is a child of %{child_title}", child_title: child_skin.title, parent_title: parent_skin.title))
end
# also don't allow duplication
end
# Takes as argument the ID of the skin to start at, and a block that should
# take a list of skin IDs and produce a list of "adjacent" skin IDs (i.e.
# parents or children).
def self.search_skin_ids(root_id)
found = Set.new([root_id])
boundary = [root_id]
until boundary.empty?
new_boundary = yield boundary
boundary = []
new_boundary.each do |skin_id|
boundary << skin_id if found.add?(skin_id)
end
end
found.delete(root_id)
found.to_a
end
def self.get_all_parent_ids(skin_id)
search_skin_ids(skin_id) do |skin_ids|
SkinParent.where(child_skin_id: skin_ids).pluck(:parent_skin_id)
end
end
def self.get_all_child_ids(skin_id)
search_skin_ids(skin_id) do |skin_ids|
SkinParent.where(parent_skin_id: skin_ids).pluck(:child_skin_id)
end
end
def parent_skin_title
self.parent_skin.try(:title) || ""
end
def parent_skin_title=(title)
self.parent_skin = Skin.find_by(title: title)
end
end