-
Notifications
You must be signed in to change notification settings - Fork 370
Segregating search documents (multi tenancy)
In a scenario where your application data may be segregated for different customers, you will want to retrieve your search results only for certain customers. This is quite straightforward when you are using search scopes on a specific model, but in a multi-search scenario with many different models, this can require some pretty complex join statements.
An alternative approach is to extend the PgSearch::Document
model to have an additional field that captures this information.
class AddCustomerIdToPgSearchDocuments < ActiveRecord::Migration
def change
add_column :pg_search_documents, :customer_id, :integer, index: true
end
end
Then in your searchable model, provide a additional_attributes
to multisearchable
. Then create a custom rebuild_pg_search_documents
for bulk loading your full dataset (if you do not provide the raw SQL for this, your re-index may be significantly slower).
class Widget < ActiveRecord::Base
include PgSearch
multisearchable against: [ :name, :description ],
additional_attributes: lambda { |widget|
{ customer_id: widget.customer_id }
},
belongs_to :customer
def self.rebuild_pg_search_documents
connection.execute <<-SQL
INSERT INTO pg_search_documents (
customer_id,
searchable_type,
searchable_id,
content,
created_at,
updated_at
)
SELECT widgets.customer_id as customer_id,
'Widget' AS searchable_type,
widgets.id AS searchable_id,
(widget.name || ' ' || widget.description) AS content,
now() AS created_at,
now() AS updated_at
FROM widgets
SQL
end
end
Then you can easily filter our the relevant results for a given customer:
PgSearch.multisearch('MyWidget').where(customer_id: 5)
Or add a method to Customer
for convenience:
class Customer < ActiveRecord::Base
has_many :widgets
def multisearch(*args)
PgSearch.multisearch(*args).where(customer_id: self.id)
end
end
Then:
customer.multisearch('MyWidget')