RubyOnRails/インクリメンタルサーチの実装

 

 

f:id:AK474747:20190803184614p:plain

インクリメンタルサーチというやつを実装したよ。

ChatSpaceでは、作ったグループ内に集まったメンバー間でのメッセージのやり取りをするという仕様なわけだけれども。

今回追加したインクリメンタルサーチは、グループ新規作成時とグループ情報編集時に、ユーザーネームを検索するという機能のために実装したよ。

コードの解説に行く前に。

インクリメンタルサーチとは

検索したい単語をすべて入力した上で検索するのではなく、入力のたびごとに即座に候補を表示させる。 逐語検索、逐次検索とも。

(引用:https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%82%AF%E3%83%AA%E3%83%A1%E3%83%B3%E3%82%BF%E3%83%AB%E3%82%B5%E3%83%BC%E3%83%81)

グーグル検索で「あ」とか打ち込むと、検索候補に「アマゾン」ってできてきたりするじゃないですか。 あれのことです。 今回はイメージしやすくていいですね。 では解説に行きます。

インクリメンタルサーチの実装

1.ルーティングなどのAPIの準備をする 今回はusers#indexを使うためのルーティングを用意します。

/config/routes.rb

Rails.application.routes.draw do
  (省略)
  resources :users  , only:[:index,:edit,:update,:show]
  (省略)
  # ただindexアクションを追加しただけです。  

 

2.テキストフィールドを作成する

これはファイルによりけりなので、ソースコードを省略します。  ちなみに僕の場合の作業ファイルは下記でした。

app/views/groups/_form.html.haml

(同階層のindex.html.hamlからrenderでformを読みだしてます。)

 

3.テキストフィールドに入力されるたびにイベントが発火するようにする

app/assets/javascripts/user.js

    $('#user-search-field').on('keyup', function(e){
        var input = $("#user-search-field").val();

'#user-search-field'がユーザー検索フォームです。 ここに文字を打ち込むたびに処理が発火します。 2行目は、変数input対して、フォームに入力された値を代入しています。

 

4.イベント時に非同期通信できるようにする


    $('#user-search-field').on('keyup', function(e){
        var input = $("#user-search-field").val();

        $.ajax({
            type: 'GET',                // HTTPメソッドはGETで
            url:  '/users',             // /usersのURLに (これによりusersコントローラのindexアクションが起動)
            data: { keyword: input},    // keyword: inputを送信する
            dataType: 'json'            // サーバから値を返す際はjsonである
        })

        .done(function(users){                // usersにjson形式のuser変数が代入される。複数形なので配列型で入ってくる
            
            if (input.length === 0) {         // フォームの文字列長さが0であれば、インクリメンタルサーチ結果を表示しないようにする
                $('#user-search-result').empty();
              }

            else if (input.length !== 0){     // 値が等しくないもしくは型が等しくなければtrueを返す。
                $('#user-search-result').empty();
                users.forEach(function(user){ // users情報をひとつずつとりだしてuserに代入
                    appendUser(user)
                });
            }

            else {
                $('#user-search-result').empty(); // ユーザーが見つからなければ「見つからない」を返す。
                appendErrMsgToHTML("一致するユーザーが見つかりません");
            }
        })

        .fail(function() {
            alert('ユーザー検索に失敗しました');
        });
    });

ちょっと長いので詳細はコメントアウトの記述に譲りますが、流れを解説します。(※appendUser(user)とappendErrMsgToHTML("一致するユーザーが見つかりません")はメソッドです。後述します。)

 

keyupにより発火。

ajaxで通信をする。その際のメソッド、リクエストの指定、データの指定、データタイプの指定をしています。

これをコントローラが受け取って、jbuilderの記述に従ってjson形式でJavaScriptに戻ってきます。 (コントローラとjbuilderの記述は冗長になるので省きます。)

done⇨通信が成功した場合は文字列の長さと型(integerかstringか)で判断します。

fail ⇨アラートを出します。

 

5.非同期通信の値を元に、HTMLに反映します。

$(document).on('turbolinks:load', function(){

    var search_list = $("#user-search-result");
    var member_list = $("#member-append");

    function appendUser(user){
        var html = 
                    `<div class="chat-group-user clearfix">
                        <p class="chat-group-user__name">${user.name}</p>
                        <div class="user-search-add chat-group-user__btn chat-group-user__btn--add" data-user-id=${user.id} data-user-name=${user.name}>追加</div>
                    </div>`;
                    search_list.append(html);
    }

    function appendErrMsgToHTML(msg){
        var html = 
                    `<div class="chat-group-user clearfix">
                        <p class="chat-group-user__name">${msg}</p>
                    </div>`;
                    search_list.append(html);
    }

4の際に記述されていた、appendUser(user)とappendErrMsgToHTML("一致するユーザーが見つかりません")のメソッドを定義しています。 ()内に記載しているのは引数です。

 

これでインクリメンタルサーチの大まかな流れは終わりです。 とっかかりは凄くハードルが高く感じますが、一個一個解説していくとそんなに難しくないかなぁと思います。

ポイントはやっぱり$.ajax内部で指定している部分かなと思います。 自動更新機能の実装なんかもしたのですが、ここの設定によるミスで頻繁にエラーが発生しました。。。

明日は自動更新機能も書きたいと思っています。