Rails搜索SQL查询

4

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

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

或者在标题中:
 @guides = Guide.where(['title LIKE ?', "%#{params[:search]}%"])

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

另外,如果有学习在Rails应用程序中使用SQL的资源建议(主要是PostgreSQL?),我将不胜感激。


这并不是你问题的简单答案,但如果你想要一个更强大的解决方案来搜索Rails应用程序,我谨虚心建议搭建一个elastic search实例并利用searchkick gem。虽然它比简单的搜索postgres类型的解决方案需要更高层次的抽象和更难的设置,但它将使你专注于你的应用程序而不是如何搜索应用程序中的数据。 - engineerDave
3个回答

7

谢谢,非常顺利地解决了问题。我真的很感激这些建议! - Jakub Kopyś
如果你认为你会经常在查询中使用OR(尽管应该尽量避免,因为它会拖慢查询性能),那么可以看看squeel gem。 - Don Pflaster

1

试试这个:

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

coalesce是在数据库中处理可能为空的值时最温柔的方法。

这将对您提供的搜索词执行整个单词、非词干匹配。您没有很多选项来调整相关性排名或使用这种天真的方案提高性能,但它可以工作!

PostgreSQL全文搜索非常强大,可能值得更复杂的选项


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Don Pflaster
那是上面的“复杂”的链接,唐! - Jim Van Fleet

1

最简单的方法是将此方法添加到您的模型中:

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

有一个更详细的答案需要关注!

使用concern是为您选择的任何模型提供搜索功能的好方法。看看这个。首先,在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

使用方法如下: 这将使所有列foobarfizbaz可以通过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')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接