如何为所有模型类提供通用搜索代码?

时间:2014-05-10 09:40:43

标签: ruby-on-rails ruby refactoring rails-activerecord decorator

我正在尝试将搜索方法重构为新类,因为我发现自己几乎在我的应用中的每个模型中使用它:

  def self.text_search(query)
    if query.present?
      where("username @@ :q or email @@ :q", q: query).order(
        updated_at: :desc)
    else
      order(updated_at: :desc)
    end
  end

参数usernameemail根据模型而变化,但我有3个模型,其中我使用相同的功能和两个不同的参数。我的想法是使用装饰器,如下所示:

class SearchModel < SimpleDelegator

    def text_search(param1, param2, options={})
        query = options[:query]
        if query.present?
            __getobj__.where("#{param1} @@ :q or #{param2} @@ :q", q:query).order(updated_at: :desc)
        else
            order(updated_at: :desc)
        end
    end
end

我这样叫SearchModel

SearchModel.new(User.all).text_search('username', 'email', query: "admin")

SearchModel.new(User.all).text_search('username', 'email')

它给了我想要的东西,但我不确定我是否以正确的方式使用装饰器。这种类型的重构是否更适合Ruby标准库的其他部分,或者这是装饰器的用途?

1 个答案:

答案 0 :(得分:1)

使用装饰器是一种比大多数人使用的更精细的方法,并导致复杂的调用语法。我会这样做:

module TextSearchSupport
  def text_search(*args)
    search_term = if args.last.responds_to(:[]) then args.pop[:query] end
    query =
      if search_term
        where(args.map { |arg| "#{arg} @@ :q" }.join(' or '), q: query)
      else
        scoped
      end
    query.order(updated_at: :desc)
  end
end
每个需要它的模型中的

extend TextSearchSupport。然后,您只需在模型上调用text_search(&#39; foo&#39;,&#39; bar&#39;,查询:&#39;查询&#39;)。

一些旁白:

  • 处理任意数量的字段而不是硬编码更好,所以我做了
  • 我认为你希望scoped而不是all来避免立即运行查询,所以我使用了它,但你说你的版本正在运行,所以不确定那里发生了什么。