我正在尝试将搜索方法重构为新类,因为我发现自己几乎在我的应用中的每个模型中使用它:
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
参数username
和email
根据模型而变化,但我有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标准库的其他部分,或者这是装饰器的用途?
答案 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
来避免立即运行查询,所以我使用了它,但你说你的版本正在运行,所以不确定那里发生了什么。