Skip to content

Commit

Permalink
Add ability to override multisearch rebuild SQL
Browse files Browse the repository at this point in the history
Now you can implement your own rebuild method to handle models that use
dynamic method calls to populate their content. This is the only way for
PgSearch::Multisearch.rebuild to work with a model that uses non-column
methods in its multisearchable :against option.
  • Loading branch information
nertzy committed Jul 8, 2012
1 parent 021b4e0 commit 4ab4f37
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
33 changes: 33 additions & 0 deletions README.rdoc
Expand Up @@ -129,6 +129,39 @@ Currently this is only supported for :against methods that directly map to Activ
PgSearch::Document.delete_all(:searchable_type => "Ingredient")
Ingredient.find_each { |record| record.update_pg_search_document }


You can also provide a custom implementation for rebuilding the documents by adding a class method called `rebuild_pg_search_documents` to your model.

class Movie < ActiveRecord::Base
belongs_to :director

def director_name
director.name
end

multisearchable against: [:name, :director_name]

# Naive approach
def self.rebuild_pg_search_documents
find_each { |record| record.update_pg_search_document }
end

# More sophisticated approach
def self.rebuild_pg_search_documents
connection.execute <<-SQL
INSERT INTO pg_search_documents (searchable_type, searchable_id, content, created_at, updated_at)
SELECT 'Movie' AS searchable_type,
movies.id AS searchable_id,
(movies.name || ' ' || directors.name) AS content,
now() AS created_at,
now() AS updated_at
FROM movies
LEFT JOIN directors
ON directors.id = movies.director_id
SQL
end
end

==== Disabling multi-search indexing temporarily

If you have a large bulk operation to perform, such as importing a lot of records from an external source, you might want to speed things up by turning off indexing temporarily. You could then use one of the techniques above to rebuild the search documents off-line.
Expand Down
6 changes: 5 additions & 1 deletion lib/pg_search/multisearch.rb
Expand Up @@ -16,7 +16,11 @@ class << self
def rebuild(model, clean_up=true)
model.transaction do
PgSearch::Document.where(:searchable_type => model.name).delete_all if clean_up
model.connection.execute(rebuild_sql(model))
if model.respond_to?(:rebuild_pg_search_documents)
model.rebuild_pg_search_documents
else
model.connection.execute(rebuild_sql(model))
end
end
end

Expand Down
23 changes: 22 additions & 1 deletion spec/pg_search/multisearch_spec.rb
Expand Up @@ -24,7 +24,7 @@
end

it "should operate inside a transaction" do
model.should_receive(:transaction).once()
model.should_receive(:transaction).once

PgSearch::Multisearch.rebuild(model)
end
Expand Down Expand Up @@ -70,6 +70,27 @@
PgSearch::Document.count.should == 2
end
end

context "when the model implements .rebuild_pg_search_documents" do
before do
def model.rebuild_pg_search_documents
connection.execute <<-SQL
INSERT INTO pg_search_documents
(searchable_type, searchable_id, content, created_at, updated_at)
VALUES
('Baz', 789, 'baz', now(), now());
SQL
end
end

it "should call .rebuild_pg_search_documents and skip the default behavior" do
PgSearch::Multisearch.should_not_receive(:rebuild_sql)
PgSearch::Multisearch.rebuild(model)

record = PgSearch::Document.find_by_searchable_type_and_searchable_id("Baz", 789)
record.content.should == "baz"
end
end
end

describe "inserting the new documents" do
Expand Down

0 comments on commit 4ab4f37

Please sign in to comment.