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