Frage

Ich habe also ein Folder- und ein FolderItem-Modell.

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

Ich verwende einen counter_cache, um die Anzahl der itens eines einzelnen Ordners zu speichern.Aber ein Ordner könnte der übergeordnete Ordner eines anderen Ordners sein, und ich wollte, dass der übergeordnete Ordner die Summe aus counter_cache aller untergeordneten Ordner und dem eigenen counter_cache enthält.

Zu diesem Zweck habe ich versucht, eine after_update-Methode einzufügen, die die in der Spalte counter_cache vorgenommenen Änderungen zwischenspeichert. Diese Methode wird jedoch beim Erstellen eines neuen FolderItem nicht aufgerufen.

War es hilfreich?

Lösung

Ich würde so etwas tun.

Fügen Sie der Ordnertabelle einige Cache-Zählerfelder hinzu

$ 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

Und Ruby-Code

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

Bitte beachten Sie, dass die Folder#sum_of_children-Methode rekursiv ist, sodass sie bei großen Datenmengen Ihre Anwendung verlangsamen kann.Vielleicht möchten Sie etwas mehr SQL-Magie daraus machen, aber als reiner Ruby ist dies einer guten Lösung so nahe wie möglich.Ich habe gesehen, dass Sie es umgekehrt gemacht haben, das wird genauso langsam sein, wie Sie es auch von unten nach oben aktualisieren müssen.(Dies ist von oben nach unten)

Sie wissen nicht, ob Sie danach suchen, aber es ist eine lesbare Lösung zum Zwischenspeichern der Anzahl der Elemente in einem Ordner.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top