Class: Decidim::ResourceSearch
- Inherits:
-
Searchlight::Search
- Object
- Searchlight::Search
- Decidim::ResourceSearch
- Defined in:
- app/services/decidim/resource_search.rb
Overview
This is the base class to be used by other search services. Searchlight documentation: github.com/nathanl/searchlight
Instance Attribute Summary collapse
-
#component ⇒ Object
readonly
Returns the value of attribute component.
-
#organization ⇒ Object
readonly
Returns the value of attribute organization.
-
#user ⇒ Object
readonly
Returns the value of attribute user.
Class Method Summary collapse
-
.text_search_fields(*fields) ⇒ Object
Public: Companion method to ‘search_search_text` which defines the attributes where we should search for text values in a model.
Instance Method Summary collapse
-
#base_query ⇒ Object
Creates the SearchLight base query.
-
#initialize(scope, options = {}) ⇒ ResourceSearch
constructor
Initialize the Searchlight::Search base class with the options provided.
-
#results ⇒ Object
We overwrite the ‘results` method to ensure we only return unique results.
-
#search_category_id ⇒ Object
Handle the category_id filter.
-
#search_origin ⇒ Object
Handle the origin filter.
-
#search_scope_id ⇒ Object
Handles the scope_ids filter.
-
#search_search_text ⇒ Object
Handle the search_text filter.
Constructor Details
#initialize(scope, options = {}) ⇒ ResourceSearch
Initialize the Searchlight::Search base class with the options provided.
scope - The scope used to create the base query options - A hash of options to modify the search. These options will be
converted to methods by SearchLight so they can be used on filter
methods. (Default {})
15 16 17 18 19 20 21 |
# File 'app/services/decidim/resource_search.rb', line 15 def initialize(scope, = {}) super() @scope = scope @user = [:current_user] || [:user] @component = [:component] @organization = [:organization] || component&.organization end |
Instance Attribute Details
#component ⇒ Object (readonly)
Returns the value of attribute component.
7 8 9 |
# File 'app/services/decidim/resource_search.rb', line 7 def component @component end |
#organization ⇒ Object (readonly)
Returns the value of attribute organization.
7 8 9 |
# File 'app/services/decidim/resource_search.rb', line 7 def organization @organization end |
#user ⇒ Object (readonly)
Returns the value of attribute user.
7 8 9 |
# File 'app/services/decidim/resource_search.rb', line 7 def user @user end |
Class Method Details
.text_search_fields(*fields) ⇒ Object
Public: Companion method to ‘search_search_text` which defines the attributes where we should search for text values in a model.
25 26 27 28 |
# File 'app/services/decidim/resource_search.rb', line 25 def self.text_search_fields(*fields) @text_search_fields = fields if fields.any? @text_search_fields end |
Instance Method Details
#base_query ⇒ Object
Creates the SearchLight base query. Check if the option component was provided.
47 48 49 50 51 |
# File 'app/services/decidim/resource_search.rb', line 47 def base_query raise "Missing component" unless component @scope.where(component: component) end |
#results ⇒ Object
We overwrite the ‘results` method to ensure we only return unique results. We can’t use ‘#uniq` because it returns an Array and we’re adding scopes in the controller, and ‘#distinct` doesn’t work here because in the later scopes we’re ordering by ‘RANDOM()` in a DB level, and `SELECT DISTINCT` doesn’t work with ‘RANDOM()` sorting, so we need to perform two queries.
The correct behaviour is backed by tests.
97 98 99 |
# File 'app/services/decidim/resource_search.rb', line 97 def results base_query.model.where(id: super.pluck(:id)) end |
#search_category_id ⇒ Object
Handle the category_id filter
54 55 56 57 58 59 60 |
# File 'app/services/decidim/resource_search.rb', line 54 def search_category_id return query if category_ids.include?("all") query .includes(:categorization) .where(decidim_categorizations: { decidim_category_id: all_category_ids }) end |
#search_origin ⇒ Object
Handle the origin filter.
82 83 84 85 86 87 |
# File 'app/services/decidim/resource_search.rb', line 82 def search_origin renamed_origin = Array(origin).map do |search_value| "#{search_value}_origin" end apply_scopes(%w(official_origin citizens_origin user_group_origin meeting_origin), renamed_origin) end |
#search_scope_id ⇒ Object
Handles the scope_ids filter. When we want to show only those that do not have a scope_ids set, we cannot pass an empty String or nil because Searchlight will automatically filter out these params, so the method will not be used. Instead, we need to pass a fake ID and then convert it inside. In this case, in order to select those elements that do not have a scope_ids set we use ‘“global”` as parameter, and in the method we do the needed changes to search properly.
69 70 71 72 73 74 75 76 77 78 79 |
# File 'app/services/decidim/resource_search.rb', line 69 def search_scope_id return query if scope_ids.include?("all") clean_scope_ids = scope_ids conditions = [] conditions << "#{query.model_name.plural}.decidim_scope_id IS NULL" if clean_scope_ids.delete("global") conditions.concat(["? = ANY(decidim_scopes.part_of)"] * clean_scope_ids.count) if clean_scope_ids.any? query.includes(:scope).references(:decidim_scopes).where(Arel.sql(conditions.join(" OR ")).to_s, *clean_scope_ids.map(&:to_i)) end |
#search_search_text ⇒ Object
Handle the search_text filter. We have to cast the JSONB columns into a ‘text` type so that we can search.
32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'app/services/decidim/resource_search.rb', line 32 def search_search_text return query unless self.class.text_search_fields.any? fields = self.class.text_search_fields.dup text_query = query.where(localized_search_text_in("#{query.model_name.plural}.#{fields.shift}"), text: "%#{search_text}%") fields.each do |field| text_query = text_query.or(query.where(localized_search_text_in("#{query.model_name.plural}.#{field}"), text: "%#{search_text}%")) end text_query end |