Reputation: 417
According to the accepted answer of this question, you should be able to use the return value of a instance method as the against parameter...
class Car < ActiveRecord::Base
include PgSearch
multisearchable :against => [:name, manufacturer_name]
belongs_to :manufacturer
def manufacturer_name
manufacturer.name
end
end
However, when I try to do this in a clean app (to rule out conflicting code in the real app) with the above model, db, etc created I get an undefined local variable or method error - what am I missing?
Upvotes: 4
Views: 1999
Reputation: 417
Ok, the short story is that the code provided in the linked post does not and cannot work as it would appear as though you cannot reference a method (instance or otherwise) in this way - which makes sense: the class needs to compile in order for the method to become available, but can't because it requires said method in order for compiling to be possible.
To achieve what I was originally attempting (without overriding pg_search) I took the following steps:
Firstly, the against declaration should use a symbol in place of the original method call.
multisearchable :against => [:name, :manufacturer_name]
This done, when an object is saved the PgSearch::Document will be created/updated using the manufacturer_name
method. However, this will break if you attempt to rebuild the search index with the following error:
ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column cars.manufacturer_name does not exist
LINE 5: ...sce("cars".name::text, '') || ' ' || coalesce("cars"...
^
: INSERT INTO "pg_search_documents" (searchable_type, searchable_id, content, created_at, updated_at)
SELECT 'Car' AS searchable_type,
"cars".id AS searchable_id,
(
coalesce("cars".name::text, '') || ' ' || coalesce("cars".manufacturer_name::text, '')
) AS content,
'2014-01-29 14:08:00.190767' AS created_at,
'2014-01-29 14:08:00.190767' AS updated_at
FROM "cars"
To fix this, override the rebuild_pg_search_documents class method which is added by the Multisearch module, to build a dynamic SQL insert query rather than reply on the existing pure SQL INSERT INTO table_name (columns) SELECT etc
query:
def self.rebuild_pg_search_documents
cars = Car.all
query_str = 'INSERT INTO pg_search_documents (searchable_type, searchable_id, content, created_at, updated_at) VALUES'
cars.each do |car|
query_str += "('Car', #{car.id}, '#{car.name} #{car.manufacturer_name}', NOW(), NOW())"
query_str += ', ' unless car == cars.last
end
query_str += ';'
connection.execute query_str
end
Hopefully this will help someone else.
Upvotes: 3