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

时间:2016-10-25 09:21:17

标签: ruby-on-rails ruby elasticsearch searchkick advanced-search

对于我的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

用户属于某个位置,通过连接表具有多个能力。换句话说:用户有一个location_id,你可以在用户上调用.competences,看看用户有哪些users_competence。

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

我的个人资料控制器:

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(搜索),但这不起作用。

我尝试了什么:

  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

1 个答案:

答案 0 :(得分:1)

TL; DR 定义search_data方法来自定义搜索索引

目前在您的代码中定义的

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

对于Searchkick 如果要返回与用户属性,权限和位置搜索匹配的用户个人资料,则应定义要通过自定义映射搜索的用户属性,权限和位置使用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
  • 因为您只想返回User个对象,所以您不需要为LocationCompetence模型编制索引(从您上面的代码中我无法对其进行索引)告诉你以前是否这样做过)