How to configure a pg_search multisearch on associ

2019-02-05 02:15发布

问题:

I'm adding pg_search into a Rails app. I'm not completely understanding the configuration, and would appreciate a gentle nudge in the right direction.

First, I already have a multi model site more or less set up and running on my app. But I want to extend it to also search on associated models.

For example, I have Manufacturer, Car, Model classes. Currently if I search for "Ford", only the manufacturer is returned. I'd also like to return all the associated Cars (which belong to Manufacturer) and Models (which belong to Car).

I can see how to do this as a scoped search

class Car
  pg_search_scope :manufactured_by, :associated_against => {
    :manufacturer => [:name]
  }
end

But if I try to do this on a multisearch it doesn't work

class Car
  include PgSearch
  multisearchable :against => [:name], 
    :associated_against => {
        :manufacturer => [:name]
      }
end

It doesn't generate an error, it simply doesn't pick up the associated records.

I have a feeling I'm missing something fundamental in my understanding of how this all fits together. I'd really appreciate if someone could help me understand this, or point me towards a good source of info. I've been through the info on github and the related Railscast, but I'm still missing something.

回答1:

It is impossible to search associated records with multisearch, due to how polymorphic associations work in Rails and SQL.

I will add an error that explains the situation so that in the future it won't be as confusing.

Sorry for the confusion.

What you could do instead is define a method on Car that returns the text you wish to search against.

class Car < ActiveRecord::Base
  include PgSearch
  multisearchable :against => [:name, manufacturer_name]
  belongs_to :manufacturer

  def manufacturer_name
    manufacturer.name
  end
end

Or to be even more succinct, you could delegate:

class Car < ActiveRecord::Base
  include PgSearch
  multisearchable :against => [:name, manufacturer_name]
  belongs_to :manufacturer
  delegate :name, :to => :manufacturer, :prefix => true
end

But you have to make sure the pg_search_documents table gets updated if you ever make a name change to a Manufacturer instance, so you should add :touch => true to its association:

class Manufacturer < ActiveRecord::Base
  has_many :cars, :touch => true
end

This way it will call the Active Record callbacks on all the Car records when the Manufacturer is updated, which will trigger the pg_search callback to update the searchable text stored in the corresponding pg_search_documents entry.