Use callbacks instead of attribute methods to update cached values

This commit is contained in:
cryptogopher 2025-04-24 18:59:36 +02:00
parent fe66522c21
commit d1593df0e0

View File

@ -18,7 +18,11 @@ class Quantity < ApplicationRecord
length: {maximum: type_for_attribute(:name).limit} length: {maximum: type_for_attribute(:name).limit}
validates :description, length: {maximum: type_for_attribute(:description).limit} validates :description, length: {maximum: type_for_attribute(:description).limit}
# Update `depth`s of progenies after parent change # Update :depths of progenies after parent change
before_update if: :parent_changed? do
self[:depth] = parent&.depth&.succ || 0
end
after_update if: :depth_previously_changed? do after_update if: :depth_previously_changed? do
quantities = Quantity.arel_table quantities = Quantity.arel_table
selected = Arel::Table.new('selected') selected = Arel::Table.new('selected')
@ -45,32 +49,28 @@ class Quantity < ApplicationRecord
) )
end end
after_update if: -> { name_previously_changed? || parent_previously_changed? } do # Update :pathnames of progenies after parent/name change
PATHNAME_DELIMITER = ' → '
before_update if: -> { parent_changed? || name_changed? } do
self[:pathname] = (parent ? parent.pathname + PATHNAME_DELIMITER : '') + self[:name]
end
after_update if: :pathname_previously_changed? do
quantities = Quantity.arel_table quantities = Quantity.arel_table
selected = Arel::Table.new('selected') selected = Arel::Table.new('selected')
# Add :name/:parent setters and update self :pathname there
Quantity.with_recursive(selected: [ Quantity.with_recursive(selected: [
quantities.project(quantities[:id].as('quantity_id'), quantities[:pathname]) quantities.project(quantities[:id].as('quantity_id'), quantities[:pathname])
.where(quantities[:id].eq(id)), .where(quantities[:id].eq(id)),
quantities.project( quantities.project(
quantities[:id], quantities[:id],
selected[:pathname].concat(Arel::Nodes.build_quoted(' → ')) selected[:pathname].concat(Arel::Nodes.build_quoted(PATHNAME_DELIMITER))
.concat(quantities[:name]) .concat(quantities[:name])
).join(selected).on(selected[:quantity_id].eq(quantities[:parent_id])) ).join(selected).on(selected[:quantity_id].eq(quantities[:parent_id]))
]).joins(:selected).update_all(pathname: selected[:pathname]) ]).joins(:selected).update_all(pathname: selected[:pathname])
end end
def parent=(value)
super
self[:depth] = parent&.depth&.succ || 0
end
def parent_id=(value)
super
self[:depth] = parent&.depth&.succ || 0
end
scope :defaults, ->{ where(user: nil) } scope :defaults, ->{ where(user: nil) }
# Return: ordered [sub]hierarchy # Return: ordered [sub]hierarchy