Rails: counter_cache non attiva il callback after_update
-
29-10-2019 - |
Domanda
Quindi, ho un modello Folder e FolderItem.
<”AGGIORNAMENTO
# == 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
Sto usando un counter_cache per mantenere il numero di itens di una singola cartella.Ma una cartella potrebbe essere la madre di un'altra cartella e volevo che la cartella principale avesse la somma di counter_cache di tutti i suoi figli più la sua counter_cache.
Per fare ciò ho provato a mettere un metodo after_update che memorizza nella cache le modifiche apportate nella colonna counter_cache, ma in qualche modo questo metodo non viene chiamato quando viene creato un nuovo FolderItem.
Soluzione
Farei qualcosa di simile.
Aggiungi alcuni campi del contatore della cache alla tabella delle cartelle
$ 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
E codice 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
Tieni presente che il metodo Folder#sum_of_children
è ricorsivo, quindi per set di dati di grandi dimensioni potrebbe rallentare l'applicazione.Potresti voler fare un po 'più di magia SQL, ma come Ruby puro questo è il più vicino a una buona soluzione che posso ottenere.Ho visto che hai fatto il contrario, sarà tanto lento quanto è necessario aggiornare anche dal basso verso l'alto.(Questo è dall'alto verso il basso)
Non so se è quello che stai cercando, ma è una soluzione leggibile per memorizzare nella cache il numero di elementi all'interno di una cartella.