【问题标题】:ROR Search virtual fieldsROR 搜索虚拟字段
【发布时间】:2015-02-04 13:51:23
【问题描述】:

我只是将搜索添加到我的项目中,以便能够按姓名查找人员。但在我的数据库中,我有 first_namelast_name 但如果有人搜索像 Joe Doe 这样的全名,则没有结果匹配

#model 
class Person < ActiveRecord::Base
  def full_name
    (self.first_name + ' ' + self.last_name).titleize
  end
end

#controller 
class PeoplesController < ApplicationController
  expose(:peoples){
    if params[:search]
      People.where(
        "first_name ILIKE ?
         OR last_name ILIKE ?
         ", params[:search], params[:search]
      )
    else
      People.all
    end
  }
end

同样,如果有人搜索 first_name 它会返回结果,last_name 它会返回结果但不是全名

如果我尝试将full_name 添加到查询中,我会得到列“full_name”不存在

感谢您的帮助

【问题讨论】:

  • 你缺少的是"%#{params[:search]}%"
  • 问题不是通配符搜索是我还想搜索 firs_name + last_name 的组合值

标签: ruby-on-rails postgresql search pg


【解决方案1】:

同样,如果有人搜索 first_name 会返回结果,last_name 会返回结果但不是全名

这是意料之中的,因为没有一个字段包含整个名称,只有部分,因此它们永远不会匹配。解决这个问题的一个简单方法是只用空格分割座位词,然后检查你是否有两个或更多项目。

# app/queries/people_search_query.rb
class PeopleSearchQuery
  attr_reader :relation

  def initialize(relation = Person.all)
    @relation = relation
  end

  def search(params)
    if params[:search]
      where_str = "first_name ILIKE ? OR last_name ILIKE ?"
      split     = params[:search].split(" ", 2)

      if split.size > 1
        relation.where(where_str, *split)
      else
        relation.where(where_str, *(split * 2))
      end
    else
      relation
    end
  end
end

class PeoplesController < ApplicationController
  expose(:peoples) { PeopleSearchQuery.new.search(params) }
end

【讨论】:

    【解决方案2】:

    虚拟字段不在数据库级别。如果不向数据库解释虚拟字段是什么,就无法进行基于数据库的搜索。

    字段的定义本质上是它所包含的列的列表。由于您使用的是 PostgreSQL,您可以通过using pg_search 来利用其全文搜索功能。它可以一次搜索多列。

    事实上,在文档中有一个几乎完全符合您的情况的示例。我真的只是在这里复制粘贴。 Go figure.

    # Model
    class Person < ActiveRecord::Base
      include PgSearch
      pg_search_scope :search_by_full_name, :against => [:first_name, :last_name]
    end
    
    # Example code for the Rails console
    person_1 = Person.create!(:first_name => "Grant", :last_name => "Hill")
    person_2 = Person.create!(:first_name => "Hugh", :last_name => "Grant")
    
    Person.search_by_full_name("Grant") # => [person_1, person_2]
    Person.search_by_full_name("Grant Hill") # => [person_1]
    

    这种东西是否值得额外依赖,取决于你。如果您发现自己需要构建许多复杂的搜索,这可能会有所帮助。

    【讨论】:

    • 喜欢你的解决方案我不得不说谢谢这真的帮了我很多。
    猜你喜欢
    • 1970-01-01
    • 2012-09-20
    • 1970-01-01
    • 2015-07-20
    • 1970-01-01
    • 1970-01-01
    • 2019-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多