プログラミング初心者の勉強ブログ #84
複数検索が可能な検索バーの実装方法についてまとめます。スペース区切りでのキーワード入力に対応するための方法です。入力内容を配列に変換することで、スペースを境にキーワードをそれぞれ分割することで、各配列要素となったキーワードを順番に検索かけていく仕組みです。
目次
実装内容
前回 【Rails】”LIKE ~ OR”を利用した簡易検索バーの実装方法(非同期処理)の続きになります。モデルに構築した検索コードを修正し、複数ワードの検索を可能にします。以下、モデルのコーディングを書いていきます。
※その他のコーディングは前回の記事参照
実際のコードと解説
Modelのコーディング
【修正前】
model/blog.rb(抜粋)
1 2 3 4 5 6 7 8 9 |
class Blog < ApplicationRecord def self.search(keyword) if keyword Blog.where(['title LIKE ? OR content LIKE ?', "%#{keyword}%", "%#{keyword}%"]) else Blog.all end end end |
前回はBlogモデルのカラムである「title」と「content」の二つに対し、キーワードの文字列と一致する内容を含むレコードを取得する記述を行いました。
今回はこれら2つのカラムに加え、「hash_01」〜「hash_04」というハッシュのカラムを更に追加しての複数ワード検索を行おうと思います。
【修正後】
models/blog.rb(抜粋)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
def self.search(keyword) if keyword && keyword != "" words = keyword.to_s.split(" ") columns = ["title", "content", "hash_01", "hash_02", "hash_03", "hash_04"] query = [] result = [] columns.each do |column| query << ["#{column} LIKE ?"] end words.each_with_index do |w, index| if index == 0 result[index] = Blog.where([query.join(" OR "), "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%"]) else result[index] = result[index-1].where([query.join(" OR "), "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%"]) end end return result[words.length-1] else Blog.all end end |
今回の処理のメインは「配列の利用」です。
1 |
words = keyword.to_s.split(" ") |
「keyword」を文字列から配列に変換しております。
例えば、keyword = "aaa bbb ccc"だとしたら、keyword = ["aaa", "bbb", "ccc"]に変換されます。今回は行なっておりませんが、間にgsupなどの置換メソッドを挟んで正規表現などを用いることで、よりバグの出ない検索機構を作ることができます。
1 |
columns = ["title", "content", "hash_01", "hash_02", "hash_03", "hash_04"] |
検索したいモデルのカラムを配列に入れてます。ここに何個カラムを格納するかで、後の 「"%#{w}%"」の個数を変えます。
1 2 3 |
columns.each do |column| query << ["#{column} LIKE ?"] end |
あらかじめ作成した「query = [ ]」配列にカラム数分要素を格納します。
1 2 3 4 5 6 7 |
words.each_with_index do |w, index| if index == 0 result[index] = Blog.where([query.join(" OR "), "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%"]) else result[index] = result[index-1].where([query.join(" OR "), "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%", "%#{w}%"]) end end |
「each_with_index」メソッドで、次は「result = [ ]」配列に検索結果を格納します。今回のような場合、検索結果を「変数」に格納すると、前回の結果に対しさらに検索をかけるようなコーディングが必要になります。「可変変数」の利用が求められますが、Rubyではこのようなとき「配列」や「ハッシュ」を用いて処理をするそうです。
そのため「each_with_index」を利用し、毎回のeachによる繰り返しごとにプラス1ずつされる「index」という変数を使って、あらかじめ定義した「result」配列に結果を一つずつ格納します。
「each_with_index」メソッドは、eachによる繰り返しの処理の度に「index」の値に数値が0,1,2...と格納される仕組みであり、初回の繰り返しの「index」は0から始まるので、「result[0]」に最初のキーワードである「words[0]」の検索結果が格納されます。
次の繰り返しでは「index = 1」となるため、「result[0]」に格納した検索結果に対し、次の「result[1]」内のキーワードにて検索をかけ、「result[1]」に結果を格納します。
if文の条件分岐により「index == 0」のときは直接Blogモデルで検索し、indexが1以上のときは前回の検索結果に対して検索をかけております。
「query.join(" OR ")」はquery配列の要素を全て「 OR 」で連結させ、一つの文字列に変換する働きがあります。
最終的に、
1 |
return result[words.length-1] |
result配列の一番最後の要素がreturnすべき検索結果であるため、「words」配列の要素数マイナス1のインデックス番号を指定してreturnします。
これで複数キーワードで、複数カラムに対して検索をかけた結果を返すことができます。
まとめ
配列と文字列をうまく利用することで、今回のような複数キーワードにも対応できる検索機能を作成できます。正規表現を使うとより高性能な検索機能になるみたいなのですが、ちょっと難しかったので正規表現の勉強が別途必要だなと思います。
以上ありがとうございました。