From da454f25acce61b2914201d4f09860aaac8217d2 Mon Sep 17 00:00:00 2001 From: Pascal Jungblut Date: Thu, 16 Nov 2017 11:16:07 +0100 Subject: [PATCH 1/2] Skip folded deeper levels when rendering page tree Previously the page tree was rendered in full even if pages are folded. Consider the following tree: even if level 1 was folded, level 2 and 3 would get rendered and sent to the client. - root |+ level 1 |- level 2 |- level 3 This change does two things: 1. load all user-folded pages for the current user in advance, reducing the number of queries to 1 2. skips all pages that are under a folded page The result is: - root |+ level 1 Together with 5a4c0d31e this speeds up the page tree rendering from 20 seconds to ~100ms when only 10 folded pages are shown (Alchemy::Page.count == 4000). --- CHANGELOG.md | 4 ++ app/models/alchemy/folded_page.rb | 5 +++ .../alchemy/page_tree_serializer.rb | 19 +++++----- spec/models/alchemy/folded_page_spec.rb | 38 +++++++++++++++++++ 4 files changed, 57 insertions(+), 9 deletions(-) create mode 100644 spec/models/alchemy/folded_page_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index c0601b2517..b1cc348c2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## 4.0.5 (unreleased) + +- Skip folded deeper levels when rendering page tree [#1324](https://github.com/AlchemyCMS/alchemy_cms/pull/1324) ([pascalj](https://github.com/pascalj)) + ## 4.0.4 (2018-09-05) - Allow Kaminari 1.x [#1467](https://github.com/AlchemyCMS/alchemy_cms/pull/1467) ([tvdeyen](https://github.com/tvdeyen)) diff --git a/app/models/alchemy/folded_page.rb b/app/models/alchemy/folded_page.rb index 261525081b..50f04da428 100644 --- a/app/models/alchemy/folded_page.rb +++ b/app/models/alchemy/folded_page.rb @@ -15,5 +15,10 @@ class FoldedPage < ActiveRecord::Base belongs_to :page, required: true belongs_to :user, required: true, class_name: Alchemy.user_class_name + + def self.folded_for_user(user) + return none unless Alchemy.user_class < ActiveRecord::Base + where(user: user, folded: true) + end end end diff --git a/app/serializers/alchemy/page_tree_serializer.rb b/app/serializers/alchemy/page_tree_serializer.rb index 1cf8d9a4c9..fd8ae77bdc 100644 --- a/app/serializers/alchemy/page_tree_serializer.rb +++ b/app/serializers/alchemy/page_tree_serializer.rb @@ -10,23 +10,24 @@ def pages tree = [] path = [{id: object.parent_id, children: tree}] page_list = object.self_and_descendants - skip_branch = false base_level = object.level - 1 + # Load folded pages in advance + folded_user_pages = FoldedPage.folded_for_user(opts[:user]).pluck(:page_id) + folded_depth = Float::INFINITY page_list.each_with_index do |page, i| has_children = page_list[i + 1] && page_list[i + 1].parent_id == page.id - folded = has_children && page.folded?(opts[:user]) + folded = has_children && folded_user_pages.include?(page.id) - if skip_branch - next if page.parent_id == path.last[:children].last[:id] - - skip_branch = false + if page.depth > folded_depth + next + else + folded_depth = Float::INFINITY end - # Do not walk my children if I'm folded and you don't need to have the - # full tree. + # If this page is folded, skip all pages that are on a higher level (further down the tree). if folded && !opts[:full] - skip_branch = true + folded_depth = page.depth end if page.parent_id != path.last[:id] diff --git a/spec/models/alchemy/folded_page_spec.rb b/spec/models/alchemy/folded_page_spec.rb new file mode 100644 index 0000000000..54bc8c0768 --- /dev/null +++ b/spec/models/alchemy/folded_page_spec.rb @@ -0,0 +1,38 @@ +require "spec_helper" + +module Alchemy + class NonArDummyUser; end + + describe FoldedPage do + describe "folded_for_user" do + subject(:folded_for_user) { described_class.folded_for_user(user) } + let(:user) { create(:alchemy_dummy_user) } + + context "with a non-AR user_class" do + around :each do |example| + before = Alchemy.user_class_name + Alchemy.user_class_name = "NonArDummyUser" + example.run + Alchemy.user_class_name = before + end + let(:user) { NonArDummyUser.new } + + it "does not raise an error" do + expect { + folded_for_user + }.not_to raise_error + end + end + + context "with folded pages" do + let(:page) { create(:alchemy_page) } + let(:other_user) { create(:alchemy_dummy_user) } + let!(:user_folded) { FoldedPage.create(user: user, page: page, folded: true) } + let!(:other_user_folded) { FoldedPage.create(user: other_user, page: page, folded: true) } + + it { is_expected.to include(user_folded) } + it { is_expected.to_not include(other_user_folded) } + end + end + end +end From adcb288b37743406d32464099476cb70109c3a13 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Mon, 20 Aug 2018 10:56:00 +0200 Subject: [PATCH 2/2] Do not cache sitemap in Turbolinks With Turbolinks caching enabled the sitemap renders twice. With large sitemaps this is already slow, doubling the request time is not nice :) --- CHANGELOG.md | 1 + app/views/alchemy/admin/pages/index.html.erb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1cc348c2f..a6dae52704 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 4.0.5 (unreleased) +- Do not cache sitemap in Turbolinks [#1463](https://github.com/AlchemyCMS/alchemy_cms/pull/1463) ([tvdeyen](https://github.com/tvdeyen)) - Skip folded deeper levels when rendering page tree [#1324](https://github.com/AlchemyCMS/alchemy_cms/pull/1324) ([pascalj](https://github.com/pascalj)) ## 4.0.4 (2018-09-05) diff --git a/app/views/alchemy/admin/pages/index.html.erb b/app/views/alchemy/admin/pages/index.html.erb index 8d1914f080..9af6c2f64d 100644 --- a/app/views/alchemy/admin/pages/index.html.erb +++ b/app/views/alchemy/admin/pages/index.html.erb @@ -1,3 +1,7 @@ +<% content_for :javascript_includes do %> + +<% end %> + <% content_for :toolbar do %>
<%= render 'alchemy/admin/partials/site_select' %>