Skip to content

Instantly share code, notes, and snippets.

@copiousfreetime
Created February 17, 2023 16:56
Show Gist options
  • Save copiousfreetime/9e87ba0ea5bc3b95d05415ca720ce04c to your computer and use it in GitHub Desktop.
Save copiousfreetime/9e87ba0ea5bc3b95d05415ca720ce04c to your computer and use it in GitHub Desktop.
Searchable Model Concern for use with pg_search
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