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éé.

Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top