使用 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
对象那么你不需要索引 Location
或 Competence
模型(从你上面的代码我不能'告诉你是否以前做过)
对于我的 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
对象那么你不需要索引Location
或Competence
模型(从你上面的代码我不能'告诉你是否以前做过)