Как я могу сделать общий код поиска доступным для всех моих классов моделей?

Я пытаюсь реорганизовать метод поиска в новый класс, потому что я использую его почти в каждой модели своего приложения:

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 params меняются в зависимости от модели, но у меня есть 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 ответ

Использование декоратора является более сложным подходом, чем большинство людей будет использовать, и приводит к сложному синтаксису вызова. Я бы сделал это так:

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 ('foo', 'bar', query: 'query') в модели.

Несколько сторон:

  • лучше обрабатывать любое количество полей, а не hardcoding, поэтому я сделал это
  • Я думаю, вы хотите, чтобы scoped а не all чтобы не запускать запрос сразу, поэтому я использовал это, но вы говорите, что ваша версия работает, поэтому не уверен, что там происходит.

licensed under cc by-sa 3.0 with attribution.