Pregunta

Entonces, tengo modelos Folder y FolderItem.

<×UPDATE

# == 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

Estoy usando un counter_cache para mantener el número de itens de una sola carpeta.Pero una carpeta puede ser la principal de otra carpeta, y quería que la carpeta principal tuviera la suma de counter_cache de todos sus hijos más su propio counter_cache.

Para hacerlo, intenté poner un método after_update que almacena en caché los cambios realizados en la columna counter_cache, pero de alguna manera este método no se llama cuando se crea un nuevo FolderItem.

¿Fue útil?

Solución

Haría algo como esto.

Agregue algunos campos de contador de caché a la tabla de carpetas

$ 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

Y código 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

Tenga en cuenta que el método Folder#sum_of_children es recursivo, por lo que para grandes conjuntos de datos puede ralentizar su aplicación.Es posible que desee hacer algo más de magia SQL, pero como Ruby puro, esto es lo más cercano a una buena solución que puedo obtener.Vi que lo hiciste al revés, eso será tan lento como necesites actualizar desde abajo hacia arriba también.(Esto es de arriba hacia abajo)

No sé si eso es lo que está buscando, pero es una solución legible para almacenar en caché la cantidad de elementos dentro de una carpeta.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top