diff --git a/db/migrate/042_add_children_count_to_articles_and_categories.rb b/db/migrate/042_add_children_count_to_articles_and_categories.rb new file mode 100644 index 0000000..2b736be --- /dev/null +++ b/db/migrate/042_add_children_count_to_articles_and_categories.rb @@ -0,0 +1,18 @@ +class AddChildrenCountToArticlesAndCategories < ActiveRecord::Migration + def self.up + add_column :articles, :children_count, :integer, :default => 0 + execute 'update articles set children_count = (select count(*) from articles a2 where (a2.parent_id = articles.id) )' + + add_column :article_versions, :children_count, :integer, :default => 0 + + add_column :categories, :children_count, :integer, :default => 0 + execute 'update categories set children_count = (select count(*) from categories c2 where (c2.parent_id = categories.id) )' + end + + def self.down + remove_column :articles, :children_count + remove_column :article_versions, :children_count + + remove_column :categories, :children_count + end +end diff --git a/db/schema.rb b/db/schema.rb index a1bd028..de9e0b3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -9,7 +9,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 41) do +ActiveRecord::Schema.define(:version => 42) do create_table "article_versions", :force => true do |t| t.integer "article_id" @@ -35,6 +35,7 @@ ActiveRecord::Schema.define(:version => 41) do t.boolean "published", :default => true t.date "start_date" t.date "end_date" + t.integer "children_count", :default => 0 end create_table "articles", :force => true do |t| @@ -61,6 +62,7 @@ ActiveRecord::Schema.define(:version => 41) do t.boolean "published", :default => true t.date "start_date" t.date "end_date" + t.integer "children_count", :default => 0 end create_table "articles_categories", :id => false, :force => true do |t| @@ -96,6 +98,7 @@ ActiveRecord::Schema.define(:version => 41) do t.float "lat" t.float "lng" t.boolean "display_in_menu", :default => false + t.integer "children_count", :default => 0 end create_table "categories_profiles", :id => false, :force => true do |t| diff --git a/lib/acts_as_filesystem.rb b/lib/acts_as_filesystem.rb index 361ac1f..8eb2bfb 100644 --- a/lib/acts_as_filesystem.rb +++ b/lib/acts_as_filesystem.rb @@ -12,12 +12,13 @@ module ActsAsFileSystem # non-alphanumericd characters changed into dashed) # * path (+:text+)- stores the full path of the object (the full path of # the parent, a "/" and the slug of the object) + # * children_count - a cache of the number of children elements. def acts_as_filesystem include ActsAsFileSystem::InstanceMethods # a filesystem is a tree - acts_as_tree :order => 'name' + acts_as_tree :order => 'name', :counter_cache => :children_count # calculate the right path before_create do |record| @@ -163,7 +164,7 @@ module ActsAsFileSystem while !current_level.empty? result += current_level - ids = current_level.map(&:id) + ids = current_level.select {|item| item.children_count > 0}.map(&:id) current_level = self.class.find(:all, :conditions => { :parent_id => ids}) end block ||= (lambda { |x| x }) diff --git a/test/unit/acts_as_filesystem_test.rb b/test/unit/acts_as_filesystem_test.rb index 4b715ea..518f81b 100644 --- a/test/unit/acts_as_filesystem_test.rb +++ b/test/unit/acts_as_filesystem_test.rb @@ -26,11 +26,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase a1 = profile.articles.build(:name => 'a1'); a1.save! - a1_1 = profile.articles.build(:name => 'a1.1'); a1_1.parent = a1; a1_1.save! - a1_2 = profile.articles.build(:name => 'a1.2'); a1_2.parent = a1; a1_2.save! + a1_1 = a1.children.create!(:name => 'a1.1', :profile => profile) - a1_1_1 = profile.articles.build(:name => 'a1.1.1'); a1_1_1.parent = a1_1; a1_1_1.save! - a1_1_2 = profile.articles.build(:name => 'a1.1.2'); a1_1_2.parent = a1_1; a1_1_2.save! + a1_2 = a1.children.create!(:name => 'a1.2', :profile => profile) + + a1_1_1 = a1_1.children.create!(:name => 'a1.1.1', :profile => profile) + a1_1_2 = a1_1.children.create!(:name => 'a1.1.2', :profile => profile) + + a1.reload assert_equivalent [a1, a1_1, a1_2, a1_1_1, a1_1_2], a1.map_traversal end @@ -40,11 +43,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase a1 = profile.articles.build(:name => 'a1'); a1.save! - a1_1 = profile.articles.build(:name => 'a1.1'); a1_1.parent = a1; a1_1.save! - a1_2 = profile.articles.build(:name => 'a1.2'); a1_2.parent = a1; a1_2.save! + a1_1 = a1.children.create!(:name => 'a1.1', :profile => profile) + + a1_2 = a1.children.create!(:name => 'a1.2', :profile => profile) - a1_1_1 = profile.articles.build(:name => 'a1.1.1'); a1_1_1.parent = a1_1; a1_1_1.save! - a1_1_2 = profile.articles.build(:name => 'a1.1.2'); a1_1_2.parent = a1_1; a1_1_2.save! + a1_1_1 = a1_1.children.create!(:name => 'a1.1.1', :profile => profile) + a1_1_2 = a1_1.children.create!(:name => 'a1.1.2', :profile => profile) + + a1.reload assert_equivalent [a1_1, a1_2, a1_1_1, a1_1_2].map(&:id), a1.all_children.map(&:id) end @@ -54,11 +60,14 @@ class ActsAsFilesystemTest < Test::Unit::TestCase a1 = profile.articles.build(:name => 'a1'); a1.save! - a1_1 = profile.articles.build(:name => 'a1.1'); a1_1.parent = a1; a1_1.save! - a1_2 = profile.articles.build(:name => 'a1.2'); a1_2.parent = a1; a1_2.save! + a1_1 = a1.children.create!(:name => 'a1.1', :profile => profile) + + a1_2 = a1.children.create!(:name => 'a1.2', :profile => profile) - a1_1_1 = profile.articles.build(:name => 'a1.1.1'); a1_1_1.parent = a1_1; a1_1_1.save! - a1_1_2 = profile.articles.build(:name => 'a1.1.2'); a1_1_2.parent = a1_1; a1_1_2.save! + a1_1_1 = a1_1.children.create!(:name => 'a1.1.1', :profile => profile) + a1_1_2 = a1_1.children.create!(:name => 'a1.1.2', :profile => profile) + + a1.reload assert_equivalent ['a1', 'a1.1', 'a1.2', 'a1.1.1', 'a1.1.2'], a1.map_traversal { |item| item.name } @@ -76,4 +85,11 @@ class ActsAsFilesystemTest < Test::Unit::TestCase assert_equal 'd', a.full_name_without_leading(3) end + should 'cache children count' do + profile = create_user('testinguser').person + a1 = profile.articles.create!(:name => 'a1') + a11 = profile.articles.create!(:name => 'a11', :parent => a1) + a12 = profile.articles.create!(:name => 'a12', :parent => a1) + end + end diff --git a/test/unit/article_test.rb b/test/unit/article_test.rb index b2072d4..f5481b7 100644 --- a/test/unit/article_test.rb +++ b/test/unit/article_test.rb @@ -55,6 +55,7 @@ class ArticleTest < Test::Unit::TestCase b.save! assert_equal 'my-article/child-article', b.path + a = Article.find(a.id); a.name = 'another name' a.save! @@ -308,4 +309,19 @@ class ArticleTest < Test::Unit::TestCase assert_includes Article.find_by_contents('anything'), art end + should 'cache children count' do + owner = create_user('testuser').person + art = owner.articles.build(:name => 'ytest'); art.save! + + # two children articles + art.children.create!(:profile => owner, :name => 'c1') + art.children.create!(:profile => owner, :name => 'c2') + + art.reload + + assert_equal 2, art.children_count + assert_equal 2, art.children.size + + end + end diff --git a/test/unit/category_test.rb b/test/unit/category_test.rb index c74e9fc..2ce2754 100644 --- a/test/unit/category_test.rb +++ b/test/unit/category_test.rb @@ -418,4 +418,17 @@ class CategoryTest < Test::Unit::TestCase assert_equivalent [c1, c11, c2], c.children_for_menu end + should 'cache children count' do + c = Category.create!(:name => 'test', :environment => Environment.default) + + # two children catagories + c.children.create!(:name => 'test1', :environment => Environment.default) + c.children.create!(:name => 'test2', :environment => Environment.default) + + c.reload + + assert_equal 2, c.children_count + assert_equal 2, c.children.size + end + end -- libgit2 0.21.2