Disallow self- and descendant-reference for base/parent

This commit is contained in:
cryptogopher 2025-01-12 19:15:43 +01:00
parent 17b4e4f8a7
commit 0652d4a89b
3 changed files with 23 additions and 0 deletions

View File

@ -8,6 +8,10 @@ class Quantity < ApplicationRecord
validate if: ->{ parent.present? } do
errors.add(:parent, :user_mismatch) unless user == parent.user
errors.add(:parent, :self_reference) if self == parent
end
validate if: ->{ parent.present? }, on: :update do
errors.add(:parent, :descendant_reference) if ancestor_of?(parent)
end
validates :name, presence: true, uniqueness: {scope: [:user_id, :parent_id]},
length: {maximum: type_for_attribute(:name).limit}
@ -99,4 +103,15 @@ class Quantity < ApplicationRecord
end
end
end
def ancestor_of?(descendant)
quantities = Quantity.arel_table
ancestors = Arel::Table.new('ancestors')
Quantity.with_recursive(ancestors: [
user.quantities.where(id: descendant.id),
user.quantities.joins(quantities.create_join(
ancestors, quantities.create_on(quantities[:id].eq(ancestors[:parent_id]))
))
]).from(ancestors).exists?(ancestors: {id: id})
end
end

View File

@ -7,6 +7,7 @@ class Unit < ApplicationRecord
validate if: ->{ base.present? } do
errors.add(:base, :user_mismatch) unless user == base.user
errors.add(:base, :self_reference) if self == base
errors.add(:base, :multilevel_nesting) if base.base.present?
end
validates :symbol, presence: true, uniqueness: {scope: :user_id},

View File

@ -23,11 +23,18 @@ en:
attributes:
base:
multilevel_nesting: has to be a top-level unit
self_reference: of an unit cannot be the unit itself
user_mismatch: has to belong to the same user as unit
multiplier:
equal_to: for a top-level unit has to be 1
symbol:
taken: has to be unique
quantity:
attributes:
parent:
descendant_reference: of the quantity cannot be its descendant
self_reference: of the quantitiy cannot be the quantity itself
user_mismatch: has to belong to the same user as quantity
actioncontroller:
exceptions:
status: