【问题标题】:Rails search SQL queryRails 搜索 SQL 查询
【发布时间】:2016-03-08 17:17:40
【问题描述】:

我正在尝试在我的 Rails 应用程序中创建搜索方法,但遗憾的是 - 我的 SQL 知识相当可悲。我设法通过以下方式找到了在描述中搜索文本的指南:

@guides = Guide.where(['description LIKE ?', "%#{params[:search]}%"])

或在标题中:

 @guides = Guide.where(['title LIKE ?', "%#{params[:search]}%"])

但我不知道如何同时查看标题和描述。请帮我解决这个问题。

此外,我希望能提供任何关于在 Rails 应用程序中使用 SQL 的资源的建议(我猜主要是 PostgreSQL?)。

【问题讨论】:

  • 这不是您问题的简单答案,但是如果您想要一个更强大的解决方案来搜索 Rails 应用程序,我会谦虚地建议建立一个弹性搜索实例并使用 searchkick gem。虽然它比简单的搜索 postgres 类型的解决方案更难设置,但它可以让您专注于您的应用程序,而不是如何搜索应用程序中的数据

标签: sql ruby-on-rails ruby postgresql search


【解决方案1】:

您可以在 SQL 查询中使用关键字“或”:

Guide.where('description LIKE :search OR name LIKE :search', search: "%#{params[:search]}%")

关于文档,你可以试试这个网站,它似乎提供了关于 SQL 的一般互动课程:http://www.sqlcourse.com/

这个网站是关于PostgreSQL的:http://www.tutorialspoint.com/postgresql/postgresql_overview.htm

另外,ILIKE 在这种情况下可能很有用(它不区分大小写)。

【讨论】:

  • 谢谢,工作就像一个魅力。我非常感谢这些建议!
  • 如果您认为您将在查询中频繁使用 OR(尽管尽量避免使用它,因为它会拖累查询性能),请查看 squeel gem。
【解决方案2】:

试试这个:

class Guide
  def self.search(term)
    where("to_tsvector(coalesce(title,'') || ' ' " +
          "|| coalesce(description,'')) @@ plainto_tsquery('english', ?)", term)
  end
end

coalesce 是该方案中对数据库中可能的空值最友好的处理方式。

这将为您提供的搜索词执行全词、非词干匹配。使用这种简单的方案,您没有太多选择来调整相关性排名或提高性能,但它会奏效!

PostgreSQL 全文搜索功能相当强大,可能值得more sophisticated options。

【讨论】:

  • 还有一个非常出色的 pg_search gem 可以轻松地为您构建这样的查询。但是,如果您发现自己在数十万到数百万行中搜索全文,请务必查看上面的“复杂”链接。
  • 这是上面的“复杂”链接,唐!
【解决方案3】:

最短的答案是将此方法标记到您的模型上:

def search_by_fields(q, fields=nil)
  sql = fields.map {|field| "#{field} LIKE ?"}.join(' OR ')
  parameters = fields.map {"%#{q}%"}
  where(sql, *parameters)
end

问题的答案更长!

使用关注点是为您选择的任何模型提供搜索功能的好方法。看一下这个。首先在您的app/models/concerns/ 中创建一个名为searchable.rb 的文件,代码如下:

#app/models/concerns/searchable.rb

module Searchable
  def self.included(base)
    base.extend(ClassMethods)
    base.include(AdapterAcknowledgeable)
  end

  module ClassMethods
    @@searchable_fields = []
    @@searchable_scope = nil

    def search(q, method=nil)
      search_method = resolve_search_method(method)
      self.send(search_method, q)
    end

    def search_by_fields(q, fields=nil)
      fields = searchable_fields unless fields
      sql = fields.map {|field| "#{field} LIKE ?"}.join(' OR ')
      parameters = fields.map {"%#{q}%"}
      where(sql, *parameters)
    end

    def search_by_scope(q, scope=nil)
      scope = searchable_scope unless scope
      scope.call(q)
    end

    def searchable_scope(scope=nil)
      @@searchable_scope = scope unless scope.nil?
      @@searchable_scope
    end

    def searchable_fields(*fields)
      @@searchable_fields = fields if fields.present?
      @@searchable_fields
    end


    private
    def resolve_search_method(method)
      method = method.downcase.to_sym unless method.nil?
      if method == :searchable_fields ||
        searchable_fields.present? && searchable_scope.nil?
        :search_by_fields
      elsif method == :searchable_scope ||
        !searchable_scope.nil? && searchable_fields.empty?
        :search_by_scope
      else
        raise "Unable to determine search method within #{self}, you must declare exactly one search method in the including class"
      end
    end
  end
end

用法如下: 这将使foo、bar、fiz 和baz 的所有列能够通过 SQL WHERE LIKE 进行查询。通过将它们与OR 连接起来,它允许它们中的任何一个匹配查询参数。

#app/models/my_searchable_model.rb

class MySearchableModel < ActiveRecord::Base
  include Searchable

  searchable_fields :foo, :bar, :fiz, :bad
end

该关注点还允许您使用 Ruby 的 lambda 语法指定范围,如下所示:

class User < ActiveRecord::Base
  include Searchable

  searchable_scope ->(q){where("first_name || ' ' || last_name LIKE ?", "%#{q}%")}
end

注意使用 SQL 连接运算符||。

现在,当我们要搜索包含关注点的模型时:

MySearchableModel.search('foo')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-10
    • 2016-01-06
    • 2010-12-03
    • 2015-03-09
    • 2011-12-06
    • 1970-01-01
    相关资源
    最近更新 更多