今回は実務で使う機会があったちょっとしたことについての記事です
やりたいこと
# keywords = ["hoge", "fuga", "piyo"]
Post.where("title LIKE ?", "%hoge%")
.or(Post.where("title LIKE ?", "%fuga%"))
.or(Post.where("title LIKE ?", "%piyo%"))
上記のように複数キーワードを渡したときに、いずれかのキーワードを含むPostを検索したい。
やり方
先に結論を書きますと、以下のようなScopeを作って対応しました
class Post < ApplicationRecord
scope :by_keywords, lambda { |keywords|
keywords.map { |keyword| where("content LIKE ?", "%#{keyword}%") }.reduce(:or)
}
end
keywords = ["hoge", "fuga", "piyo"]
Post.by_keywords(keywords)
他に見かけたやり方だと、、、
keywords = ["hoge", "fuga", "piyo"]
@posts = Post.none
keywords.each do |keyword|
@posts = @posts.or(Post.where("content LIKE ?", "%#{keyword}%"))
end
return @posts
のようなeachで回すやり方です。Post.none
をしたり、@posts
に再代入が行われるのも違和感がありました。
reduceでorを繋げるなら1行でいけますし、当然1クエリで済むので個人的に気に入りました。