LoginSignup
125
129

More than 5 years have passed since last update.

Railsでajaxを用いた簡単なインクリメンタルサーチを実装する

Last updated at Posted at 2017-05-17

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

検索窓に文字を入力すると、入力ごとに候補を表示させる検索方法です。
Googleで何か文字を打つと、検索窓の下に、ピョコンと検索候補が出てきますよね。
あれです。

対象読者

インクリメンタルサーチに恐怖を覚えている人。
rails、jqueryの基礎はある程度理解している人。

準備

まず、サンプルとなるアプリケーションを作っていきましょう。
今回は、scaffoldを使用して進めていきます。
ユーザーの名前と年齢を登録できるアプリケーションを作成してみます。
ターミナルで、以下のコマンドを打ち込みます。

ターミナル
rails new scaffold_sample
rails g scaffold user name:string age:integer

すると、MVCで必要なファイルを一気に作成し、ルーティングまで設定してくれます。さらにbundle installまで行ってくれます。
マイグレーションファイルを確認して、データベースを作成しましょう。

db/migrate/0000000000_create_users.rb
class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :name
      t.integer :age

      t.timestamps
    end
  end
end
ターミナル
rake db:migrate

これでデータベースも作成され、準備が整いました。
サーバーを立ち上げ、http://localhost:3000/users に接続し、正しく表示がされているか確認してみましょう。

ターミナル
rails s

スクリーンショット 2017-05-17 19.52.48.png

画像のように表示されていれば成功です。
では、試しにユーザー登録をしてみます。
ユーザー情報がデータベースにしっかりと登録ができていれば、下の画像のように表示されます。

スクリーンショット 2017-05-17 19.54.23.png

インクリメンタルサーチを実装する

さて、ここからいよいよインクリメンタルサーチを実装していきます。
検索語句を入力したら、その度にユーザー名が表示されるようなものを作っていきます。

ビューを編集する

まずは、検索窓をビューに作りましょう。
inputタグを使い、フォームを作ります。

app/views/index.html.erb
<h1>Users</h1>
<!-- ここから追記 -->
<input type=form id="form" placeholder="ユーザー名を入力してください" style="width: 250px;"/>

jsファイルでは、id(もしくはクラス)を指定して実装を進めるので、必ずidを付与しておきます。

jsファイルで、検索語句を取得する

さて、これだけでは何も意味を持たないフォームができただけですね。
このフォームの情報をjsファイルで取得できるようにしましょう。
app/assets/javascriptに、user.js(名前は任意)というファイルを作成します。
その中に、以下のような記述を加えます。

app/assets/javascript/user.js
$(document).on('turbolinks:load', function(){ //リロードしなくてもjsが動くようにする
  $(document).on('keyup', '#form', function(e){ //このアプリケーション(document)の、formというid('#form')で、キーボードが押され指が離れた瞬間(.on('keyup'...))、eという引数を取って以下のことをしなさい(function(e))
    e.preventDefault(); //キャンセル可能なイベントをキャンセル
    var input = $.trim($(this).val()); //この要素に入力された語句を取得し($(this).val())、前後の不要な空白を取り除いた($.trim(...);)上でinputという変数に(var input =)代入
  });
});

これでユーザーが入力した検索語句を取得することができました。

ajaxを用いてデータを渡す

このデータを、ajax通信を用いて、json形式でコントローラーに渡します。
下記のように追記しましょう。

app/assets/javascript/user.js
$(document).on('turbolinks:load', function(){
    $(document).on('keyup', '#form', function(e){
    e.preventDefault();
    var input = $.trim($(this).val());
    //ここから追記
    $.ajax({ //ajax通信で以下のことを行います
      url: '/users/search', //urlを指定
      type: 'GET', //メソッドを指定
      data: ('keyword=' + input), //コントローラーに渡すデータを'keyword=input(入力された文字のことですね)'にするように指定
      processData: false, //おまじない
      contentType: false, //おまじない
      dataType: 'json' //データ形式を指定
    })
  });
});

これで、ajax通信でデータをコントローラーに渡すことができました。

コントローラーを編集する

さて、ajaxにてURLは'/users/search'に、メソッドは'GET'を指定しました。
これの通り、ルーティングとコントローラーを設定します。

config/routes.rb
Rails.application.routes.draw do
  resources :users do
    collection do
      get 'search'
    end
  end
end
app/controllers/users_controller.rb
def search
end
# privateの前に追記

このsearchアクションの中でデータを受け取り、検索をかけたいですね。
また、新たにsearchというビューをつくるのではなく、検索した名前はindexに表示させたいので、そのような処理もここに書きましょう。

app/controllers/users_controller.rb
def search
  @users = User.where('name LIKE(?)', "%#{params[:keyword]}%") #paramsとして送られてきたkeyword(入力された語句)で、Userモデルのnameカラムを検索し、その結果を@usersに代入する
  respond_to do |format| 
    format.json { render 'index', json: @users } #json形式のデータを受け取ったら、@usersをデータとして返す そしてindexをrenderで表示する
  end
end

以下のように書くとよりすっきりします。

app/controllers/users_controller.rb
def search
  @users = User.where('name LIKE(?)', "%#{params[:keyword]}%")
  render json: @users
end

コントローラーで検索された内容をjsで表示できるようにする

さて、今@usersにはフォームに入力された語句と部分一致したユーザーの名前の情報が入っています。
この中から、一人ずつ名前を表示できるようにしたいですね。
ここから、一気に書いていきます。

まずは、ビューに検索結果を表示させる場所を作りましょう。
リストとして表示させたいので、ulタグを用意しておきます。

app/views/index.html.erb
<input type=form id="form" placeholder="ユーザー名を入力してください" style="width: 250px;"/>
<!-- ここから追記 -->
<ul id="result">
<!-- この中に<li>デデデ大王</li>みたいに検索候補を追加していきます -->
</ul>

次に、ulタグの中に検索結果を表示させるコードを書いていきます。
まず、.doneを書きます。
意味としては、「ajax通信が成功したら」、という意味だと考えて良いでしょう。
そして、dataという形で、コントローラーで作成した@usersがjsに渡されています。
それを、each文で一つずつ取り出し、名前を表示させます。

app/assets/javascript/user.js
$(document).on('turbolinks:load', function(){
    $(document).on('keyup', '#form', function(e){
    e.preventDefault();
    var input = $.trim($(this).val());
    $.ajax({
      url: '/users/search',
      type: 'GET',
      data: ('keyword=' + input),
      processData: false,
      contentType: false,
      dataType: 'json'
    })
    //ここから追記
    .done(function(data){ //データを受け取ることに成功したら、dataを引数に取って以下のことする(dataには@usersが入っている状態ですね)
      $('#result').find('li').remove();  //idがresultの子要素のliを削除する
      $(data).each(function(i, user){ //dataをuserという変数に代入して、以下のことを繰り返し行う(単純なeach文ですね)
        $('#result').append('<li>' + user.name + '</li>') //resultというidの要素に対して、<li>ユーザーの名前</li>を追加する。
      });
    })
  });
});

これで全ての実装が終わりました!
見た目はしょぼいですが、以下のように表示されていれば成功です!
スクリーンショット 2017-05-17 21.27.01.png

('#result').find('li').remove();という記述をしているのは、同じユーザーネームでも、文字を打つたびに検索結果が追加されていってしまうからです。
例えば、'aaaaa'という名前のユーザーがいるとします。

aと入力→
aaaaa
と表示される
aaと入力→
aaaaa
aaaaa
と表示される
aaaと入力→
aaaaa
aaaaa
aaaaa
と表示される

実際に試してみると、そのような挙動をするはずです。
これを回避するために、このような記述が必要なのです。

最後に

最後まで読んでくださってありがとうございます!
インクリメンタルサーチと聞くと、それだけで難しい気がしてしまいますが、実際に行っていることを一つずつ追ってみると、以外と単純だったりします。

文字が入力される
↓
jsで読み取る
↓
コントローラーにjson形式でajax通信でデータを渡す
↓
そのデータを元に、like句を使って検索
↓
検索結果をjsに返す
↓
受け取ったデータをappendで表示する

私自身初心者ですが、わからないときは1から順に片付けていくと良いみたいですね!

参考資料

記事中では全く解説しなかったものについて、解説してくれているサイトたちです。

scaffold(スキャフォールド)について
覚えておくと超便利!Ruby on Railsのscaffoldの使い方【初心者向け】

Turbolinksについて
Turbolinks 5とTurbolinks Classic(2.x)の比較

preventDefault()について
preventDefault()について

ajaxについて
はじめてajaxを使うときに知りたかったこと

jsonとは
RailsでJSON形式のデータを取得し、結果を画面に表示させる

collection doについて
Rails のルーティング

LIKE句について
Railsであいまい検索(LIKE)やAND検索を行う

125
129
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
125
129