문제

I am trying to refactor a search method into a new class because I find myself using it in nearly every model in my app:

  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

The params username and email change depending on the model, but I have 3 models where I use the same functionality with two different params. My idea is to use a decorator, like this:

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

I am calling SearchModel like this:

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

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

and it gives me what I want, but I am not sure if I am using a decorator in the correct way. Would this type of refactor be more appropriate in some other part of Ruby's standard library, or is this what decorators are for?

도움이 되었습니까?

해결책

Using a decorator is a more elaborate approach than most people would use, and leads to a complicated calling syntax. I would do it like this:

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

and extend TextSearchSupport in each model that needs it. Then you can just call text_search('foo', 'bar', query: 'query') on the model.

A couple of asides:

  • it is nicer to handle any number of fields rather than hardcoding, so I did that
  • I think you want scoped rather than all to avoid running the query right away, so I used that, but you say your version was working so not sure what was going on there.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top