まえがき
インクリメンタルサーチを実装するにあたって結構な時間を費やしてしまったので備忘録として書きます。実装をしてる方の役に立てると幸いです。
#インクリメンタルサーチとは
どんなサイトにも当たり前のように付いている機能ですが、検索フォームに文字を打ち込んだ際に、enterを押さなくても自動的に結果が表示されるものです。有名なもので言うと、googleの検索欄なんかがインクリメンタルサーチになっています。
#実装の流れ
・ルーティングを設定
・コントローラーにアクションを設定
・jbuilderの作成、記述
・フォームを作成
・発火させるようにjsに記述
・jsに追記
・modelにsearchメソッドを定義
・controllerに追記
・done関数の処理の記述
・非同期通信のビュー作成
・htmlをビュー上に描画
#ルーティングを設定
resources :samples, only: :index
collection do
get 'search'
end
今回はsearchメソッドをモデルで定義して使うので、今のうちにsearchのルーティングを設定しておきます。
#コントローラーにアクションを設定
先ほど設定したsearchアクションをコントローラーに記述し、編集していきます。
def search
respond_to do |format|
format.html
format.json
end
end
この記述により、サーバーはjson形式で値をかえし、jbuilderファイルを使えるようになります。
この後出てくるjbuilderで@sampleと言う変数を使っていますが、また後述しますのでいったんこのまま進めます。
#jbuilderの作成、記述
先ほどコントローラーに記述したrespond_toで分岐した情報がもしもjsonで送られた時はその情報はjbuilderへと流れてきます。
jbuilderの役割としては、html形式だった情報をjsonに変換して、非同期でhtml上で表示をさせることができる形に変換することです。
jbuilderの記載方法は以下です。
json.array! @samples do |sample|
json.title sample.title
json.content sample.content
json.name sample.user.name
end
今回は検索フォームということで配列として一つ一つの情報を順番に取り出せるようにしました。
json.array! @samples do |sample|
という部分で配列にするという指定をしています。
実際に変換をしているコードを説明していきます。
json.title sample.title
この部分で説明をすると、まず、arrayで指定をした一つ一つの値を|sample|
として書いているのでその変数sampleの中に入っているtitleをjsonのtitleという名前に置き換えています。半角空白から右側が変換前、左側が変換後です。このjbuilderで変換した値は次はコントローラーへ送られ、その後jsファイルの.done
へと送られるので覚えておきましょう。
#フォームを作成
次に実際に検索の文字を打ち込む検索フォームを作っていきます。
.search_form
= form_with(url: search_samples_path, local: true, method: :get, class: "search-form") do |form|
= form.text_field :keyword, placeholder: "検索", class: "search-input"
今回はform_withを使って記述しています。
現在form_withが最も推奨されたフォームなので、form_forやform_tagなどを使っている方は早めにform_withを使えるようにしておきましょう。
= form.submit "検索", class: "search-btn"
本来このような検索ボタンがフォームには付いていますが、今回はインクリメンタルサーチと言うことで、あえて外しました。
#発火できるようにjsに記述
$(function() {
$(".search-input").on("keyup", function() {
let input = $(".search-input").val();
console.log(input);
});
});
発火を確認できるようにconsole.log(input)
を記述しておきました。
このコードの意味としては.search-input
をkeyup(キーボードから指あげた時)にその値を.val
で取得し、inputに代入後、console.log(input)
でデバッグを行っています。
もし発火していたら、ブラウザ上のプロパティツールでconsoleを選択し、入れた値を確認することができます。
jsに追記
$(function() {
$(".search-input").on("keyup", function() {
let input = $(".search-input").val();
$.ajax({
type: 'GET',
url: '/sample/search',
data: { keyword: input },
dataType: 'json'
});
});
一つ一つ説明をしていきます。
$ajaxはコントローラーにリクエストを送る処理のことです。
**type:**ではHTTPメソッドを指定しています。
**url:**ではデータを送る先のurlを指定しています。
**data:**ではコントローラーに送るデータを指定しています。
data: { keyword: input },
の部分では、input
という変数を:keyword
というキーをつけて送るよということが書いてあります。
**dataType:**は送るdataの形式を指定しています。
#modelにsearchメソッドを定義
ここでsearchメソッドを定義していきます。
def self.search(search)
return Sumple.all() unless search
Sumple.where('title LIKE(?)', "%#{search}%")
end
titleと引数で持ってきたserachを比べて曖昧検索をするというメソッドを定義しました。
これで**.search**というメソッドを使えるようになりました。
#controllerに追記
def search
@input = Sample.search(params[:keyword])
respond_to do |format|
format.html
format.json
end
end
コントローラーにサーチメソッドを使う処理を書いていきます。ここでsearchメソッドに引数で
(params[:keyword])
を送ることでフォームで打ち込んだ文字が検索にかけられるようになっています。
#done関数の処理の記述
$(function() {
$(".search-input").on("keyup", function() {
let input = $(".search-input").val();
$.ajax({
type: 'GET',
url: '/tweets/search',
data: { keyword: input },
dataType: 'json'
})
.done(function(samples) {
$(".contents.row").empty();
if (samples.length !== 0) {
samples.forEach(function(sample){
appendSample(sample);
});
}
else {
appendErrMsgToHTML("一致するツイートがありません");
}
})
});
});
このような形で記述します。
.doneとはjbuilderから送られてきた情報を受け取るところです。受け取った情報をどのように使うかという表記をしています。
#非同期通信のビュー作成
var search_list = $(".contents.row");
function appendSample(sample) {
var current_user = sample.user_sign_in && sample.user_sign_in.id == sample.user_id ?
`<li>
<a href="/samples/${sample.id}/edit" data-method="get" >編集</a>
</li>
<li>
<a href="/samples/${sample.id}" data-method="delete" >削除</a>
</li>` : "";
var html = `<div class="content_post" style="background-image: url(${sample.image});">
<div class="more">
<span><img src="/assets/arrow_top.png"></span>
<ul class="more_list">
<li>
<a href="/samples/${sample.id}" data-method="get" >詳細</a>
</li>
${current_user}
</ul>
</div>
<p>${sample.text}</p><br>
<span class="name">
<a href="/users/${sample.user_id}">
<span>投稿者</span>${sample.nickname}
</a>
</span>
</div>`
search_list.append(html);
}
function appendErrMsgToHTML(msg) {
var html = `<div class='name'>${ msg }</div>`
search_list.append(html);
}
この記述をjsファイル上部に記載します。この記載がjson形式のデータが入るインクリメンタルサーチが動作したときに表示されるビューファイルです。
.fail(function() {
alert('error');
});
最後に.done表記の下にもしデータ送信が失敗したときの対処も記載しておきましょう。
#あとがき
以上でインクリメンタルサーチの実装は終了です。MVCモデルやajaxをしっかりと理解していないとどこからどこに情報が流れているかということがわからなくなってしまうので、情報の流れや、どの変数を使用しているのかということをしっかりと考えることがすごく大切です。もしわからないところがあれば随所調べるようにしましょう。
では、お疲れ様でした!!