Skip to content

Commit

Permalink
Add search page module and remove controller extension
Browse files Browse the repository at this point in the history
The controller methods were available on every page in Alchemy and was listening to the query param. This approach is not really extendable, if you need multiple parameter to process the search result.
The main logic was moved into a SearchPage module which has nearly the same structure as before, but is now way more flexible, because it is only used in this particular page layout. It also allows the application to extend the search and the view without monkey patching the gem.
The only downside is, that it isn't possible anymore to add a search string the searchresults - element to test the search in the admin interface.
  • Loading branch information
sascha-karnatz committed Oct 11, 2024
1 parent 7418988 commit b73f2cd
Show file tree
Hide file tree
Showing 12 changed files with 109 additions and 144 deletions.
37 changes: 6 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ In order to render the search results, you'll need a page layout that represents
page layout as `searchresults: true`. The search form will pick this page as result page.

#### Search Results Page

Add a search layout to the `page_layout.yml` and mark it with a `searchresults` flag. These flag is used to find the
correct page path for search form.

```yaml
# page_layouts.yml
Expand All @@ -143,40 +146,12 @@ page layout as `searchresults: true`. The search form will pick this page as res
unique: true
```

Tip: For maximum flexibility you could also add an element that represents the search results. This lets your editors to
place additional elements (maybe a header image or additional text blocks) on the search result page.

```yaml
# page_layouts.yml
- name: search
searchresults: true
unique: true
elements:
- searchresults
autogenerate:
- searchresults
# elements.yml
- name: searchresults
unique: true
ingredients:
- role: search_string
hint: The is only for presentational purposes in the Alchemy preview
default: lorem
type: Text
```

and then use the view helpers to render the search form on the page layout partial and the search results on the element
view partial.
and then use the view helpers to render the search form on the page layout partial.

```erb
<!-- app/views/alchemy/page_layouts/_search.html.erb -->
<%= render_elements %>
<!-- app/views/alchemy/elements/_searchresults.html.erb -->
<%= element_view_for(searchresults) do |el| -%>
<%= render_search_results %>
<%- end -%>
<% @search_results = Alchemy::Search::Page.perform_search(params, ability: current_ability) %>
<%= render_search_results %>
```

### View Helpers
Expand Down
96 changes: 0 additions & 96 deletions app/controller/alchemy/pg_search/controller_methods.rb

This file was deleted.

3 changes: 2 additions & 1 deletion app/helpers/alchemy/pg_search/search_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ def render_search_form(options = {})
class: "fulltext_search",
id: "search",
}
render "alchemy/search/form", options: default_options.merge(options), search_result_page: search_result_page
search_result_page = Alchemy::Search::SearchPage.search_result_page
render "alchemy/search/form", options: default_options.merge(options), search_result_page:
end

# Renders the search results partial within +app/views/alchemy/search/_results.html+
Expand Down
38 changes: 38 additions & 0 deletions app/services/alchemy/search/search_page.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

module Alchemy
module Search
module SearchPage
def self.perform_search(params, ability: nil)
search_results = Alchemy.search_class.search(params[:query], ability:)
search_results = search_results&.page(params[:page])&.per(paginate_per) if paginate_per.present?
search_results
end

def self.paginate_per
Alchemy::PgSearch.config[:paginate_per]
end

def self.search_result_page
@search_result_page ||= begin
page_layouts = PageLayout.all.select do |page_layout|
page_layout.key?(:searchresults) && page_layout[:searchresults].to_s.casecmp(true.to_s).zero?
end

if page_layouts.nil?
raise "No searchresults page layout found. Please add page layout with `searchresults: true` into your `page_layouts.yml` file."
end

page = Page.published.find_by(
page_layout: page_layouts.first["name"],
language_id: Language.current.id,
)
if page.nil?
logger.warn "\n++++++\nNo published search result page found. Please create one or publish your search result page.\n++++++\n"
end
page
end
end
end
end
end
4 changes: 0 additions & 4 deletions lib/alchemy/pg_search/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ class Engine < ::Rails::Engine
require_dependency(c)
end

# We need to have the search methods present in all Alchemy controllers
Alchemy::PagesController.send(:include, Alchemy::PgSearch::ControllerMethods)
Alchemy::Admin::PagesController.send(:include, Alchemy::PgSearch::ControllerMethods)

# In development environment, this runs on every code reload, so avoid multiple reindexing jobs
unless Alchemy.publish_targets.map(&:name).include? 'Alchemy::PgSearch::IndexPageJob'
# reindex the page after it was published
Expand Down

This file was deleted.

This file was deleted.

3 changes: 2 additions & 1 deletion spec/dummy/app/views/alchemy/page_layouts/_search.html.erb
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
<% @search_results = Alchemy::Search::SearchPage.perform_search(params, ability: current_ability) %>
<%= render_search_form %>
<%= render_elements %>
<%= render_search_results %>
3 changes: 0 additions & 3 deletions spec/dummy/config/alchemy/elements.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,6 @@
type: Picture
searchable: false

- name: searchresults
unique: true

- name: content_test
ingredients:
- role: without_searchable
Expand Down
4 changes: 0 additions & 4 deletions spec/dummy/config/alchemy/page_layouts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,3 @@
- name: search
searchresults: true
unique: true
elements:
- searchresults
autogenerate:
- searchresults
2 changes: 1 addition & 1 deletion spec/features/fulltext_search_feature_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

RSpec.describe "Fulltext search" do
let!(:search_page) do
create(:alchemy_page, :public, name: "Suche", page_layout: "search", autogenerate_elements: true)
create(:alchemy_page, :public, name: "Suche", page_layout: "search")
end

it "form has correct path in the form tag" do
Expand Down
60 changes: 60 additions & 0 deletions spec/services/alchemy/search/search_page_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require "spec_helper"

RSpec.describe Alchemy::Search::SearchPage do
let(:paginate_per) { 10 }
before do
Alchemy::PgSearch.config = {
paginate_per:,
}
end

context "#perform_search" do
let(:query) {"foo"}
let(:params) { {query:}}
subject { described_class.perform_search(params, ability: nil) }

it "calls the Alchemy.search_class" do
expect(Alchemy.search_class).to receive(:search).with(query, ability: nil)
subject
end

context "pagination" do
let(:query) {"page"}

before do
12.times do
create(:alchemy_page, :public)
end
Alchemy.search_class.rebuild
end

it "response with 10 documents" do
expect(subject.length).to eq(10)
end

context "without pagination" do
let(:paginate_per) { nil }

it "response with all documents" do
expect(subject.length).to eq(12)
end
end
end
end

context '#paginate_per' do
subject { described_class.paginate_per }

it 'should be 10 if no configuration is set' do
expect(subject).to eq(10)
end

context "with configuration" do
let(:paginate_per) { 50 }

it 'should be 50 if no configuration is set' do
expect(subject).to eq(50)
end
end
end
end

0 comments on commit b73f2cd

Please sign in to comment.