From 342d6b3600cd41599b65a22fd8e3f64b347d46f5 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Wed, 20 Feb 2019 11:30:13 +0100 Subject: [PATCH] Use the ElementsFinder in Page#find_elements The element find logic is now abstracted into the elements finder. If you have custom element finding logic, you can pass your own elements finder instance to the method as options[:finder]. This custom class needs to implement the interface of Alchemy::ElementsFinder. --- app/models/alchemy/page.rb | 32 +++++++++++++ app/models/alchemy/page/page_elements.rb | 37 -------------- spec/models/alchemy/page_spec.rb | 53 +++++---------------- spec/rails_helper.rb | 1 + spec/support/custom_news_elements_finder.rb | 7 +++ 5 files changed, 53 insertions(+), 77 deletions(-) create mode 100644 spec/support/custom_news_elements_finder.rb diff --git a/app/models/alchemy/page.rb b/app/models/alchemy/page.rb index 766be8a949..acca8640f7 100644 --- a/app/models/alchemy/page.rb +++ b/app/models/alchemy/page.rb @@ -289,6 +289,38 @@ def new_name_for_copy(custom_name, source_name) # Instance methods # + # Returns elements from page. + # + # @option options [Array|String] :only + # Returns only elements with given names + # @option options [Array|String] :except + # Returns all elements except the ones with given names + # @option options [Integer] :count + # Limit the count of returned elements + # @option options [Integer] :offset + # Starts with an offset while returning elements + # @option options [Boolean] :include_hidden (false) + # Return hidden elements as well + # @option options [Boolean] :random (false) + # Return elements randomly shuffled + # @option options [Boolean] :reverse (false) + # Reverse the load order + # @option options [Class] :finder (Alchemy::ElementsFinder) + # A class that will return elements from page. + # Use this for your custom element loading logic. + # + # @return [ActiveRecord::Relation] + def find_elements(options = {}, show_non_public = false) + if show_non_public + Alchemy::Deprecation.warn "Passing true as second argument to page#find_elements to include" / + " invisible elements has been removed. Please implement your own ElementsFinder" / + " and pass it with options[:finder]." + end + + finder = options[:finder] || Alchemy::ElementsFinder.new(options) + finder.elements(page: self) + end + # The page's view partial is dependent from its page layout # # == Define page layouts diff --git a/app/models/alchemy/page/page_elements.rb b/app/models/alchemy/page/page_elements.rb index 1eb24d919e..6d1bf66c5f 100644 --- a/app/models/alchemy/page/page_elements.rb +++ b/app/models/alchemy/page/page_elements.rb @@ -61,43 +61,6 @@ def copy_elements(source, target) end end - # Finds elements of page. - # - # @param [Hash] - # options hash - # @param [Boolean] (false) - # Pass true, if you want to also have not published elements. - # - # @option options [Array] only - # Returns only elements with given names - # @option options [Array] except - # Returns all elements except the ones with given names - # @option options [Fixnum] count - # Limit the count of returned elements - # @option options [Fixnum] offset - # Starts with an offset while returning elements - # @option options [Boolean] random (false) - # Return elements randomly shuffled - # - # @return [ActiveRecord::Relation] - # - def find_elements(options = {}, show_non_public = false) - elements = self.elements - if options[:only].present? - elements = elements.named(options[:only]) - elsif options[:except].present? - elements = elements.excluded(options[:except]) - end - if options[:reverse_sort] || options[:reverse] - elements = elements.reverse_order - end - elements = elements.offset(options[:offset]).limit(options[:count]) - if options[:random] - elements = elements.order("RAND()") - end - show_non_public ? elements : elements.published - end - # All available element definitions that can actually be placed on current page. # # It extracts all definitions that are unique or limited and already on page. diff --git a/spec/models/alchemy/page_spec.rb b/spec/models/alchemy/page_spec.rb index 46d66c7d52..786b5184cd 100644 --- a/spec/models/alchemy/page_spec.rb +++ b/spec/models/alchemy/page_spec.rb @@ -1103,52 +1103,25 @@ module Alchemy end describe '#find_elements' do - before do - create(:alchemy_element, public: false, page: public_page) - create(:alchemy_element, public: false, page: public_page) - end + subject { page.find_elements(options) } - context "with show_non_public argument TRUE" do - it "should return all elements from empty options" do - expect(public_page.find_elements({}, true).to_a).to eq(public_page.elements.to_a) - end - - it "should only return the elements passed as options[:only]" do - expect(public_page.find_elements({only: ['article']}, true).to_a).to eq(public_page.elements.named('article').to_a) - end - - it "should not return the elements passed as options[:except]" do - expect(public_page.find_elements({except: ['article']}, true).to_a).to eq(public_page.elements - public_page.elements.named('article').to_a) - end - - it "should return elements offsetted" do - expect(public_page.find_elements({offset: 2}, true).to_a).to eq(public_page.elements.offset(2)) - end + let(:page) { build(:alchemy_page) } + let(:options) { {} } + let(:finder) { instance_double(Alchemy::ElementsFinder) } - it "should return elements limitted in count" do - expect(public_page.find_elements({count: 1}, true).to_a).to eq(public_page.elements.limit(1)) - end + it 'passes self and all options to elements finder' do + expect(Alchemy::ElementsFinder).to receive(:new).with(options) { finder } + expect(finder).to receive(:elements).with(page: page) + subject end - context "with show_non_public argument FALSE" do - it "should return all elements from empty arguments" do - expect(public_page.find_elements.to_a).to eq(public_page.elements.published.to_a) - end - - it "should only return the public elements passed as options[:only]" do - expect(public_page.find_elements(only: ['article']).to_a).to eq(public_page.elements.published.named('article').to_a) - end - - it "should return all public elements except the ones passed as options[:except]" do - expect(public_page.find_elements(except: ['article']).to_a).to eq(public_page.elements.published.to_a - public_page.elements.published.named('article').to_a) - end - - it "should return elements offsetted" do - expect(public_page.find_elements({offset: 2}).to_a).to eq(public_page.elements.published.offset(2)) + context 'with a custom finder given in options' do + let(:options) do + { finder: CustomNewsElementsFinder.new } end - it "should return elements limitted in count" do - expect(public_page.find_elements({count: 1}).to_a).to eq(public_page.elements.published.limit(1)) + it 'uses that to load elements to render' do + expect(subject.map(&:name)).to eq(['news']) end end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 8b4aebdcae..387d48f828 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -26,6 +26,7 @@ require_relative "support/hint_examples.rb" require_relative "support/transformation_examples.rb" require_relative "support/capybara_select2.rb" +require_relative 'support/custom_news_elements_finder' ActionMailer::Base.delivery_method = :test ActionMailer::Base.perform_deliveries = true diff --git a/spec/support/custom_news_elements_finder.rb b/spec/support/custom_news_elements_finder.rb new file mode 100644 index 0000000000..1c32d5f170 --- /dev/null +++ b/spec/support/custom_news_elements_finder.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class CustomNewsElementsFinder + def elements(*) + [Alchemy::Element.new(name: 'news', id: 1001)] + end +end