2012-02-22 94 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,这已经接近我可以得到的一个很好的解决方案。我看到你以相反的方式做了这件事,那也会像你需要从下往上更新一样慢。 (这是自上而下)

不知道这是否是你要找的,但它是一个可读的解决方案缓存文件夹中的项目数。