То, что вы ищете, это «кеш счетчика». Он реализует именно то, что вы пытаетесь сделать. ActiveRecord может сделать это за вас:
belongs_to :post, :counter_cache => true
Есть пара гемов, которые делают это, обновляя поле счетчика в родительской записи всякий раз, когда дочерняя запись создается или удаляется.
Драгоценный каменьcounter-cache
делает работу просто. Другой вариант, counter-culture
, делает это немного дальше, включая поддержку подсчета детей в отношениях has_many :through
.
Ваш пример немного интереснее, поскольку вы ищете не счет, а вычислениесчет. Таким образом, вы можете либо просто свернуть с этим и использовать его для вычисления pack_volume на лету, возможно, в методе на модели, очень похожем на ваш метод compute_packed_volume()
.
Если вы хотите сохранить фактический объемв вашей родительской записи (возможно, это очень дорого для вычисления), вам нужно перейти от установки обратных вызовов в родительской модели к размещению их в дочерней модели. Драгоценный камень counter_culture
поддерживает это с помощью "Delta Magnitude". Примерно так:
class Item < ActiveRecord::Base
belongs_to :order
counter_culture :order, column_name: :packed_volume, delta_magnitude: 0.1
end
class Order < ActiveRecord::Base
has_many :items
end
Параметр delta_magnitude
может взять процесс, так что вы можете делать более сложные вещи. Возможно, что-то вроде этого:
counter_culture :order, column_name: :packed_volume, delta_magnitude: -> {|item| item.length * item.width * item.height }
Вы можете накатить свое собственное решение по этим направлениям, если у вас есть другие требования, исключающие использование драгоценного камня. Вам нужно будет добавить обратные вызовы для Item для after_create
и before_destroy
, чтобы увеличить / уменьшить родительскую запись. Вам также может понадобиться обновить порядок при изменении записи, если ваши вычисления объема становятся более сложными.