Question

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?

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top