diff --git a/.gitignore b/.gitignore index 0e341b3..b1f7195 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ Gemfile.lock spec/dummy/log/*.log spec/dummy/db/*.sqlite3* spec/dummy/tmp/* +spec/dummy/public/* +spec/dummy/uploads/* .ruby-* node_modules yarn.lock diff --git a/app/extensions/alchemy/pg_search/ingredient_extension.rb b/app/extensions/alchemy/pg_search/ingredient_extension.rb index 8823fd0..6e0d620 100644 --- a/app/extensions/alchemy/pg_search/ingredient_extension.rb +++ b/app/extensions/alchemy/pg_search/ingredient_extension.rb @@ -1,13 +1,18 @@ module Alchemy::PgSearch::IngredientExtension - def self.prepended(base) - base.include PgSearch::Model - base.multisearchable( + + def self.multisearch_config + { against: [ :value, ], additional_attributes: ->(ingredient) { { page_id: ingredient.element.page.id } }, - if: :searchable?, - ) + if: :searchable? + } + end + + def self.prepended(base) + base.include PgSearch::Model + base.multisearchable(multisearch_config) end def searchable? @@ -17,4 +22,8 @@ def searchable? end end +# add the PgSearch model to all ingredients Alchemy::Ingredient.prepend(Alchemy::PgSearch::IngredientExtension) + +# # only enable the search for Text, Richtext, and Picture +Alchemy::Ingredients::Picture.multisearchable(Alchemy::PgSearch::IngredientExtension.multisearch_config.merge({against: [:caption]})) diff --git a/spec/dummy/config/alchemy/elements.yml b/spec/dummy/config/alchemy/elements.yml index 5583470..1cc2326 100644 --- a/spec/dummy/config/alchemy/elements.yml +++ b/spec/dummy/config/alchemy/elements.yml @@ -70,3 +70,14 @@ type: EssencePicture nestable_elements: - article + +- name: ingredient_test + ingredients: + - role: ingredient_text + type: Text + - role: ingredient_richtext + type: Richtext + - role: ingredient_picture + type: Picture + nestable_elements: + - article diff --git a/spec/lib/search_spec.rb b/spec/lib/search_spec.rb index fb87f8b..a0955a4 100644 --- a/spec/lib/search_spec.rb +++ b/spec/lib/search_spec.rb @@ -2,17 +2,21 @@ describe Alchemy::PgSearch::Search do let(:page_version) { create(:alchemy_page_version, :published) } - let(:element) { create(:alchemy_element, :with_contents, name: "essence_test", public: true, page_version: page_version) } + let(:essence_element) { create(:alchemy_element, :with_contents, name: "essence_test", public: true, page_version: page_version) } + let(:ingredient_element) { create(:alchemy_element, :with_ingredients, name: "ingredient_test", public: true, page_version: page_version) } + let(:prepared_essences) do { :essence_text => :body, :essence_richtext => :body, :essence_picture => :caption }.each do |essence_name, field| - essence = element.content_by_name(essence_name).essence + essence = essence_element.content_by_name(essence_name).essence essence[field] = "foo" essence.save end end let(:prepared_ingredients) do - Alchemy::PgSearch::SEARCHABLE_INGREDIENTS.each do |ingredient_type| - create(:"alchemy_ingredient_#{ingredient_type.downcase}", value: "foo", element: element) + { :ingredient_text => :value, :ingredient_richtext => :value, :ingredient_picture => :value }.each do |ingredient_name, field| + ingredient = ingredient_element.ingredient_by_role(ingredient_name) + ingredient[field] = "foo" + ingredient.save end end let(:first_page) { Alchemy::Page.first } @@ -121,7 +125,7 @@ end context 'nested elements' do - let(:nested_element) { create(:alchemy_element, :with_contents, name: "article", public: true, page_version: page_version, parent_element: element) } + let(:nested_element) { create(:alchemy_element, :with_contents, name: "article", public: true, page_version: page_version, parent_element: essence_element) } before do nested_element diff --git a/spec/models/ingredient_spec.rb b/spec/models/ingredient_spec.rb index 88807f6..bb07aee 100644 --- a/spec/models/ingredient_spec.rb +++ b/spec/models/ingredient_spec.rb @@ -1,112 +1,117 @@ require "spec_helper" -describe Alchemy::Ingredient do - let(:element) do - page_version = create(:alchemy_page_version, :published) - create(:alchemy_element, :with_contents, name: "ingredient_test", public: true, page_version: page_version) - end +RSpec.shared_examples_for "it is searchable" do + describe "searchable?" do + subject { ingredient.searchable? } + + context "element and ingredient are searchable" do + it { is_expected.to be(true) } + + context "but configured as not searchable" do + before do + expect(ingredient).to receive(:definition).at_least(:once) do + { + searchable: false, + } + end + end - Alchemy::PgSearch::SEARCHABLE_INGREDIENTS.each do |ingredient_type| - describe ingredient_type do - let(:ingredient) { create(:"alchemy_ingredient_#{ingredient_type.downcase}", value: "foo", element: element) } + it { is_expected.to be(false) } + end + end - describe "searchable?" do - subject { ingredient.searchable? } + context "ingredient has no content" do + it "should be not searchable" do + ingredient.value = nil + expect(ingredient.searchable?).to be(false) + end + end - context "element and ingredient are searchable" do - it { is_expected.to be(true) } + context "element is not public" do + it "should be not searchable" do + element.public = false + expect(ingredient.searchable?).to be(false) + end + end - context "but configured as not searchable" do - before do - expect(ingredient).to receive(:definition).at_least(:once) do - { - searchable: false, - } - end - end + context "ingredient has no related content" do + let(:ingredient) { create(:alchemy_ingredient_text) } - it { is_expected.to be(false) } - end - end + it "should be not searchable" do + expect(ingredient.searchable?).to be(false) + end + end + end +end - context "ingredient has no content" do - it "should be not searchable" do - ingredient.value = nil - expect(ingredient.searchable?).to be(false) - end - end +RSpec.shared_examples_for "it is in search index" do + describe "search index" do + let(:document) { PgSearch::Document.first } - context "element is not public" do - it "should be not searchable" do - element.public = false - expect(ingredient.searchable?).to be(false) - end - end + subject do + ingredient + ::PgSearch::Multisearch.rebuild described_class + end + + it "should have one entry" do + subject + expect(PgSearch::Document.where(searchable_type: "Alchemy::Ingredient").count).to eq(1) + end - context "ingredient has no related content" do - let(:ingredient) { create(:alchemy_ingredient_text) } + it "should have the content" do + subject + expect(PgSearch::Document.first.content).to eq(content) + end - it "should be not searchable" do - expect(ingredient.searchable?).to be(false) - end + context "configured as not searchable" do + before do + expect_any_instance_of(ingredient.class).to receive(:definition).at_least(:once) do + { + searchable: false, + } end end - context "index" do - let(:document) { PgSearch::Document.first } + it "should have no index entry" do + subject + expect(PgSearch::Document.where(searchable_type: "Alchemy::Ingredient").count).to eq(0) + end + end - subject do - ingredient - ::PgSearch::Multisearch.rebuild Alchemy::Ingredient - end + it "should be the current ingredient" do + subject + expect(document.searchable).to eq(ingredient) + end + end +end - it "should have one entry" do - subject - expect(PgSearch::Document.where(searchable_type: "Alchemy::Ingredient").count).to eq(1) - end +describe Alchemy::Ingredient do + let(:element) do + page_version = create(:alchemy_page_version, :published) + create(:alchemy_element, :with_contents, name: "ingredient_test", public: true, page_version: page_version) + end - context "configured as not searchable" do - before do - expect_any_instance_of(ingredient.class).to receive(:definition).at_least(:once) do - { - searchable: false, - } - end - end + let(:content) { "foo bar"} - it "should have no index entry" do - subject - expect(PgSearch::Document.where(searchable_type: "Alchemy::Ingredient").count).to eq(0) - end - end + describe Alchemy::Ingredients::Text do + let(:ingredient) { create(:alchemy_ingredient_text, value: content, element: element) } - it "should be the current ingredient" do - subject - expect(document.searchable).to eq(ingredient) - end - end - end + it_behaves_like "it is searchable" + it_behaves_like "it is in search index" end - context "not supported ingredient type" do - let(:ingredient) { create(:"alchemy_ingredient_boolean", value: true, element: element) } + describe Alchemy::Ingredients::Richtext do + let(:ingredient) { create(:alchemy_ingredient_richtext, value: content, element: element) } + let(:ingredient_class) { Alchemy::Ingredients::Text } - context "searchable?" do - it "should be not searchable" do - expect(ingredient.searchable?).to be(false) - end - end + it_behaves_like "it is searchable" + it_behaves_like "it is in search index" + end - context "index" do - let(:document) { PgSearch::Document.first } - before do - ingredient - ::PgSearch::Multisearch.rebuild Alchemy::Ingredient - end + describe Alchemy::Ingredients::Picture do + let(:ingredient) { create(:alchemy_ingredient_picture, value: create(:alchemy_picture), caption: content, element: element) } - it "should have no entries" do - expect(PgSearch::Document.all.length).to eq(0) - end - end + it_behaves_like "it is searchable" + it_behaves_like "it is in search index" end end