Я бы сделал что-то подобное.
Добавление некоторых полей счетчика кэша в таблицу папок
$ rails g migration add_cache_counters_to_folders child_folders_count:integer \
folder_items_count:integer \
total_items_count:integer \
sum_of_children_count:integer
и код Ruby
class Folder < ActiveRecord::Base
belongs_to :parent_folder, class_name: 'Folder', counter_cache: :child_folders_count
has_many :child_folders, class_name: 'Folder', foreign_key: :parent_folder_id
has_many :folder_items
before_save :cache_counters
# Direct descendants - files and items within this folder
def total_items
child_folders_count + folder_items_count
end
# All descendants - files and items within all the folders in this folder
def sum_of_children
folder_items_count + child_folders.map(&:sum_of_children).inject(:+)
end
private
def cache_counters
self.total_items_count = total_items
self.sum_of_children_count = sum_of_children
end
end
class FolderItem < ActiveRecord::Base
belongs_to :folder, counter_cache: true # folder_items_count
end
Обратите внимание, что метод Folder#sum_of_children
является рекурсивным, поэтому для больших наборов данных он может замедлить работу вашего приложения. Возможно, вы захотите сделать с ним больше магии SQL, но для чистого Ruby это как можно ближе к хорошему решению. Я видел, что вы сделали это с другой стороны, это будет так же медленно, как и обновление снизу вверх. (Это сверху вниз)
Не знаю, ищите ли вы это, но это удобочитаемое решение для кэширования количества элементов в папке.