使用 searchkick 设置高级搜索,处理与多个模型的关联 (Rails)

Setting up an advanced search with searchkick, coping with associations with multiple models (Rails)

对于我的 Rails 应用程序,我正在尝试使用 Searckick (elasticsearch) 设置高级搜索。我想做的是:

到目前为止我已经修复了它,我可以搜索一个用户,但我不确定如何也可以搜索这些其他模型。

我的路线:

Rails.application.routes.draw do
  ActiveAdmin.routes(self)
  devise_for :users, controllers: {sessions: "sessions", registrations:       
  "registrations"}
  # For details on the DSL available within this file, see
  http://guides.rubyonrails.org/routing.html

  root 'pages#home'

  get "/news", to: 'pages#news'

  get "welcome_back", to: 'pages#welcome_back'

  get "/profile", to: "profile#show"

  resources :profiles do
    collection do
      get :autocomplete
    end
  end

  namespace :profile do
    resources :locations
    resources :positions
    resources :competences
  end
end

一个用户属于一个位置,通过加入 table 拥有多个能力。换句话说:用户拥有 location_id,您可以对用户调用 .competences,以查看用户拥有哪个 users_competences。

谁能告诉我如何设置此搜索?

我的配置文件控制器:

class ProfilesController < ApplicationController

  def index
    query = params[:search].presence || "*"
    @users = User.search(query, suggest: true, operator: "or")
  end

  def autocomplete
    render json: ["Test"]
  end

end

我尝试在我的模型中使用 def self(search),但这不起作用。

我尝试了什么:

  def self.search(search)
       where(["User.first_name LIKE ?","%#{search}%"])
       where(["User.last_name LIKE ?","%#{search}%"])
       where(["User.competences.collect{&:name} IN ?","%#{search}%"])
       joins(:location).where("location.name LIKE ?", "%#{search}%")
     else
       all
     end
   end

TL;DR 定义一个 search_data 方法来自定义您的搜索索引

当前在您的代码中定义的

self.search 不正确 您的 self.search 方法将是一种通过 ActiveRecord 和您正在使用的任何数据库进行搜索的方法。这不是您通过 Searchkick 进行搜索的方式。

对于 Searchkick 如果您想要 return 匹配搜索用户属性、能力和位置的用户配置文件,那么您应该定义用户属性、能力和您要使用 search_data 方法通过自定义映射搜索的位置,已记录 here:

class User < ActiveRecord::Base
  searchkick locations: ["location"]
  # this line will eager load your assocations
  scope :search_import, -> { includes(:location, :competences) }

  def search_data
    {
      first_name: first_name,
      last_name: last_name,
      competences: competences.map(&:name),
      # from your code above it looks like you want to search location.name
      location_name: location.name
      # the following merged hash would allow you to search by location latitude and 
      # longitude coordinates if you have them
      ## if you don't use latitude and longitude then you don't need to include 
      ## `locations: ["location"] when you call searchkick in the User model on line 2 
      ## above or the merged location hash below
    }.merge(location: {lat: location.latitude, lon: location.longitude})
  end
end

现在您在 Profiles#index 操作中的搜索查询将起作用:

@users = User.search(query, suggest: true, operator: "or")

不需要您定义的self.search方法。

其他注意事项

  • 我假设因为您在查询中包含 suggest: true,所以您正确定义了关于用户模型的建议:

    class User < ActiveRecord::Base
      searchkick locations: ["location"], suggest: [:first_name, :last_name, :location_name] # or whatever fields you want
    end
    
  • 确保reindex
  • 因为你只想 return User 对象那么你不需要索引 LocationCompetence 模型(从你上面的代码我不能'告诉你是否以前做过)