2012-02-22 69 views
1

所以,我有一個Folder和一個FolderItem模型。Rails:counter_cache不會觸發after_update回調

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 

我使用counter_cache保持一個文件夾的itens的數量。但是一個文件夾可能是另一個文件夾的父文件夾,並且我希望父文件夾具有所有子項的counter_cache加上它自己的counter_cache的總和。

爲此,我嘗試將after_update方法緩存在counter_cache列中進行的更改,但不知何故在創建新FolderItem時未調用此方法。

+0

一些實際的代碼,看看它爲什麼不被調用會很好。像FolderItem類一樣?這聽起來像你將不得不編寫完整的自定義緩存代碼,因爲counter_cache並不是用於Folder.has_many:items以外的其他任何內容。你在做什麼是Folder.has_many:文件夾,它本身有很多文件夾。 – tombruijn 2012-02-22 17:19:07

+0

只需添加代碼。我仍然認爲我所做的事應該是可能的,但是我認爲它不起作用,因爲處理counter_cache的方式,我猜它就像嵌套的嵌套SQL,所以rails代碼被忽略。但我只想確定一下。 – 2012-02-22 17:38:12

回答

1

我會做這樣的事情。

添加一些緩存計數器字段文件夾表

$ 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 

和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 

請注意,Folder#sum_of_children - 方法是遞歸的,所以對於大型數據集,可能你的應用程序變慢。你可能想對它做更多的SQL魔術,但是作爲純Ruby,這已經接近我可以得到的一個很好的解決方案。我看到你以相反的方式做了這件事,那也會像你需要從下往上更新一樣慢。 (這是自上而下)

不知道這是否是你要找的,但它是一個可讀的解決方案緩存文件夾中的項目數。