Created
February 17, 2023 16:56
-
-
Save copiousfreetime/9e87ba0ea5bc3b95d05415ca720ce04c to your computer and use it in GitHub Desktop.
Searchable Model Concern for use with pg_search
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Searchable | |
extend ActiveSupport::Concern | |
included do | |
include PgSearch::Model | |
class_attribute :searchable_attributes, default: [] | |
class_attribute :searchable_internal_attributes, default: [] | |
multisearchable against: [ | |
:searchable_attributes_text, | |
:custom_searchable_text | |
], | |
# See `internal_content` method below | |
additional_attributes: -> (doc) { { internal_content: doc.internal_content } }, | |
internal_against: [ | |
:searchable_internal_attributes_text, | |
:custom_internal_searchable_text | |
] | |
end | |
# Helper method so that Models can search just themselves from within the | |
# multisearch index | |
class_methods do | |
def search_scope(q) | |
PgSearch::Document.search(q).where(searchable_type: self.base_class.name) | |
end | |
def search(q) | |
# use select here instead of pluck because it will make it a single query | |
# instead of 2 queries | |
self.where(id: search_scope(q).select(:searchable_id)) | |
end | |
def internal_search_scope(q) | |
PgSearch::Document.internal_search(q).where(searchable_type: self.base_class.name) | |
end | |
def internal_search(q) | |
self.where(id: internal_search_scope(q).select(:searchable_id)) | |
end | |
end | |
# Meta programming so that modles can just set an class attribute of all the | |
# attributes that are searchable | |
# | |
def searchable_attributes_text | |
Array.new.tap do |a| | |
searchable_attributes.each do |f| | |
a << self.send(f) | |
end | |
end.compact.join(" ") | |
end | |
def related_searchable_objects | |
[] | |
end | |
def custom_searchable_text | |
Array.new.tap do |a| | |
related_searchable_objects.each do |related| | |
a << related_object_searchable_text(related) | |
end | |
end.compact.join(" ") | |
end | |
def related_object_searchable_text(related) | |
return nil unless related.present? | |
return nil unless related.kind_of?(Searchable) | |
return related.searchable_attributes_text | |
end | |
# Basically equivalent to PgSearch::Mutisearchable#searchable_text | |
def internal_content | |
pg_search_multisearchable_options[:internal_against].map do |symbol| | |
send(symbol) | |
end.compact.join(" ") | |
end | |
def searchable_internal_attributes_text | |
Array.new.tap do |a| | |
searchable_internal_attributes.each do |f| | |
a << self.send(f) | |
end | |
end.compact.join(" ") | |
end | |
def custom_internal_searchable_text | |
Array.new.tap do |a| | |
related_searchable_objects.each do |related| | |
a << related_object_searchable_internal_text(related) | |
end | |
end.compact.join(" ") | |
end | |
def related_object_searchable_internal_text(related) | |
return nil unless related.present? | |
return nil unless related.kind_of?(Searchable) | |
return related.searchable_internal_attributes_text | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment