ActiveRecordで複数カラムをLIKE検索して、特定のカラムにヒットしたものを優先して並び替えたい
と思っていろいろ考えた。
最初はselect
に引数として
CASE WHEN name LIKE #{quoted_keyword} THEN 1 ELSE 0 END AS match_name
を指定して order('match_name desc')
としてみたけど、
検索結果を count()
するとActiveRecordが勝手に COUNT(DISTINCT CASE ... AS match_name )
というInvalidなSQLを組み立てたので、あえなく断念した。
(この場合でも count に引数を指定すればちゃんと動く)
もしやこんなのいけるか〜 と思って
order()
に↑の CASE WHEN ...
を引数として指定したら動いた。
以下例
def search_by_keyword(keyword)
search_columns = [:name, :email, :profile, :company, :address]
or_wheres = search_columns.map { |c| arel_table[c].match(keyword) }
quoted_keyword = ActiveRecord::Base.connection.quote(keyword)
where(or_wheres.inject(:or))
.order("CASE WHEN name LIKE #{quoted_keyword} THEN 1 ELSE 0 END desc")
end