diff --git a/vendor/engines/your_platform/app/models/dag_link.rb b/vendor/engines/your_platform/app/models/dag_link.rb index 26cffd4bd..317b4cd4c 100644 --- a/vendor/engines/your_platform/app/models/dag_link.rb +++ b/vendor/engines/your_platform/app/models/dag_link.rb @@ -6,6 +6,7 @@ class DagLink < ActiveRecord::Base after_create :delete_cache after_save :delete_cache + after_destroy :delete_cache def delete_cache ancestor.delete_cache if ancestor.try(:respond_to?, :delete_cache) diff --git a/vendor/engines/your_platform/app/models/group.rb b/vendor/engines/your_platform/app/models/group.rb index 7dd9aeacb..4c170d2a1 100644 --- a/vendor/engines/your_platform/app/models/group.rb +++ b/vendor/engines/your_platform/app/models/group.rb @@ -41,6 +41,7 @@ class Group < ActiveRecord::Base after_create :import_default_group_structure # from GroupMixins::Import def delete_cache + Structureable delete_cache_structureable delete_cached_leaf_groups end diff --git a/vendor/engines/your_platform/app/models/page.rb b/vendor/engines/your_platform/app/models/page.rb index 9445af0bc..70bb068ca 100644 --- a/vendor/engines/your_platform/app/models/page.rb +++ b/vendor/engines/your_platform/app/models/page.rb @@ -10,6 +10,7 @@ class Page < ActiveRecord::Base belongs_to :author, :class_name => "User", foreign_key: 'author_user_id' def delete_cache + Structureable delete_cache_structureable end @@ -39,7 +40,7 @@ def to_param # def <<(child) unless child.in? self.children - if child.in? self.descendants + if child.in? self.descendants(true) link = DagLink.where( ancestor_type: 'Page', ancestor_id: self.id, descendant_type: child.class.name, descendant_id: child.id diff --git a/vendor/engines/your_platform/app/models/structureable.rb b/vendor/engines/your_platform/app/models/structureable.rb index 88401c544..2a08466fa 100644 --- a/vendor/engines/your_platform/app/models/structureable.rb +++ b/vendor/engines/your_platform/app/models/structureable.rb @@ -121,7 +121,24 @@ def destroy_links end def delete_cache_structureable + delete_cached_descendants delete_cache_roles end + + def delete_cached_descendants + Rails.cache.delete([self, 'descendants']) + end + + def cached_descendants + Rails.cache.fetch([self, 'descendants'], expires_in: 1.week) do + descendants(true) + end + end + + def descendants(force_reload = false) + descendant_pages(true) if force_reload && self.respond_to?(:descendant_pages) + descendant_groups(true) if force_reload && self.respond_to?(:descendant_groups) + descendants + end end end diff --git a/vendor/engines/your_platform/app/models/user.rb b/vendor/engines/your_platform/app/models/user.rb index 536a5f4f7..9ccce8184 100644 --- a/vendor/engines/your_platform/app/models/user.rb +++ b/vendor/engines/your_platform/app/models/user.rb @@ -719,7 +719,7 @@ def administrated_objects( role = :admin ) objects = directly_administrated_objects( role ) if objects objects += objects.collect do |directly_administrated_object| - directly_administrated_object.descendants + directly_administrated_object.cached_descendants end.flatten objects else diff --git a/vendor/engines/your_platform/app/presenters/horizontal_nav_presenter.rb b/vendor/engines/your_platform/app/presenters/horizontal_nav_presenter.rb index 4797d9ebf..014f96c24 100644 --- a/vendor/engines/your_platform/app/presenters/horizontal_nav_presenter.rb +++ b/vendor/engines/your_platform/app/presenters/horizontal_nav_presenter.rb @@ -63,7 +63,7 @@ def navable_is_most_special_category?( navable ) def most_special_category categories_the_current_navable_falls_in.try(:select) do |navable| - (navable.descendants & categories_the_current_navable_falls_in).empty? + (navable.cached_descendants & categories_the_current_navable_falls_in).empty? end.try(:first) end diff --git a/vendor/engines/your_platform/spec/models/structureable_spec.rb b/vendor/engines/your_platform/spec/models/structureable_spec.rb index 120297ac9..0622dbab7 100644 --- a/vendor/engines/your_platform/spec/models/structureable_spec.rb +++ b/vendor/engines/your_platform/spec/models/structureable_spec.rb @@ -9,26 +9,120 @@ describe Structureable do - describe ".is_structureable" do + describe '.is_structureable' do - before { @node = create( :page ) } + before { @node = create(:page) } subject { @node } - it "should provide the has_dag_links functionality" do - subject.should respond_to( :parents, :children, :ancestors, :descendants ) + it 'should provide the has_dag_links functionality' do + subject.should respond_to(:parents, :children, :ancestors, :descendants) end - it "should provide the has_many_flags functionality" do - subject.should respond_to( :flags, :add_flag, :remove_flag ) + it 'should provide the has_many_flags functionality' do + subject.should respond_to(:flags, :add_flag, :remove_flag) end - it "should make sure that when objects are destroyed, also their dag links are destroyed" do - @parent = create( :page ) + it 'should make sure that when objects are destroyed, also their dag links are destroyed' do + @parent = create(:page) @parent.child_pages << @node @node.destroy @parent.links_as_parent.count.should == 0 end + end + describe '#descendants' do + before do + @node = create(:page) + end + subject { @node.descendants } + it { should == [] } + describe 'after adding child' do + before do + @child = create(:page) + @node.child_pages << @child + end + it { should include @child } + end + describe 'after adding grandchildren' do + before do + @child = create(:page) + @grandchild = create(:page) + @node.child_pages << @child + @child.child_pages << @grandchild + end + it { should include @grandchild } + end end + describe '#cached_descendants' do + before do + @node = create(:page) + end + subject { @node.cached_descendants } + it { should == [] } + describe 'after adding child' do + before do + @node.cached_descendants + @child = create(:page) + @node.child_pages << @child + end + it { should include @child } + end + describe 'after adding grandchildren' do + before do + @node.cached_descendants + @child = create(:page) + @grandchild = create(:page) + @node.child_pages << @child + @child.child_pages << @grandchild + end + it { should include @grandchild } + end + describe 'after removing grandchildren' do + before do + @child = create(:page) + @grandchild = create(:page) + @node.child_pages << @child + @child.child_pages << @grandchild + @node.cached_descendants + @grandchild.destroy_dag_links + end + it { should_not include @grandchild } + end + describe 'after multiple adding and removing' do + before do + @p1 = create(:page) + @p2 = create(:page) + @p3 = create(:page) + @p4 = create(:page) + @p5 = create(:page) + @p6 = create(:page) + @p7 = create(:page) + @node.cached_descendants + @node.child_pages << @p1 + @p1.child_pages << @p2 + @node.cached_descendants + @p2.child_pages << @p4 + @node.cached_descendants + @node.child_pages << @p3 + @node.cached_descendants + @node.child_pages << @p5 + @p5.child_pages << @p6 + @node.cached_descendants + @p2.destroy_dag_links + @node.cached_descendants + @p5.child_pages << @p7 + @node.cached_descendants + @p6.destroy_dag_links + end + it { should include @p1 } + it { should_not include @p2 } + it { should include @p3 } + it { should_not include @p4 } + it { should include @p5 } + it { should_not include @p6 } + it { should include @p7 } + end + end end +