Rails: Counter_Cache ne déclenche pas le rappel après_update
-
29-10-2019 - |
Question
J'ai donc un dossier et des modèles de folderitem.
METTRE À JOUR
# == Schema Information
#
# Table name: folders
#
# id :integer not null, primary key
# name :string(255) not null
# parent_folder_id :integer
# user_id :integer not null
# folder_itens_count :integer default(0)
# created_at :datetime
# updated_at :datetime
#
class Folder < ActiveRecord::Base
...
belongs_to :parent_folder, :class_name => 'Folder'
has_many :child_folders, :class_name => 'Folder', :foreign_key => :parent_folder_id
has_many :folder_itens, :order => 'created_at DESC'
after_update {
update_parent_folder_itens_count
}
def update_parent_folder_itens_count
parent_folder = self.parent_folder
if self.folder_itens_count_changed? && parent_folder
quant_changed = self.folder_itens_count - self.folder_itens_count_was
parent_folder.increment(:folder_itens_count, quant_changed)
end
end
end
class FolderItem < ActiveRecord::Base
...
belongs_to :folder, :counter_cache => :folder_itens_count
end
J'utilise un Counter_Cache pour conserver le nombre d'itérations d'un seul dossier. Mais un dossier pourrait être le parent d'un autre dossier, et je voulais que le dossier parent ait la somme de Counter_Cache de tous ses enfants plus son propre compteur_cache.
Pour ce faire, j'ai essayé de mettre une méthode After_update en cachant les modifications apportées dans la colonne Counter_Cache, mais d'une manière ou d'une autre, cette méthode n'est pas appelée lorsqu'un nouveau folderite est créé.
La solution
Je ferais quelque chose comme ça.
Ajoutez des champs de comptoir de cache à la table des dossiers
$ 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
Et code rubis
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
Veuillez noter que le Folder#sum_of_children
-Méthod est récursif, donc pour les grands ensembles de données, il peut ralentir votre application. Vous voudrez peut-être y faire plus de SQL-magique, mais en tant que rubis pur, c'est aussi proche d'une bonne solution que possible. J'ai vu que vous l'avez fait l'inverse, ce sera aussi lent que vous devez également mettre à jour de bas en haut. (C'est de haut en bas)
Je ne sais pas si c'est ce que vous recherchez, mais c'est une solution lisible pour mettre en cache le nombre d'articles dans un dossier.