Railsでtypeahead.jsを使ったオートコンプリート機能(入力補完機能)の実装手順

はじめに
Railsアプリ内の入力フォームでユーザの入力に合わせた候補を表示するオートコンプリート機能をTwitter社が提供しているtypeahead.jsを使って実装したのでその手順をメモしておきます。
やりたいこと
以下のgifのように、ユーザがフォームで入力を行った時に、その入力内容に合わせた候補を自動で表示するというオートコンプリート機能を実装します。以下のようにNameのテキストフィールドではNameの候補を表示し、EmailのテキストフィールドではEmailの候補を表示できるようにします。なお、以下の例では新規ユーザ作成フォームでの名前とE-mailの入力に対してオートコンプリート機能を実装した例になりますが、これ自体は実用上はなんの意味もないです。
 このような機能をお手軽に実装するのに
このような機能をお手軽に実装するのにtypeahead.jsというライブラリをTwitter社が提供しているので、これを使います。
typeahead.jsの動作概要
以下の図がtypeahead.jsの簡単な動作イメージになります。
 上記のような動作を実現するために、以下の作業が必要になります。
上記のような動作を実現するために、以下の作業が必要になります。
- Viewでユーザの入力を検知してtypeaheadを動作させるjavascriptの追加
- ViewからControllerにパラメータを送るためにroutes.rbにルートを追加(routes.rbの修正)
- パラメータを元に候補ワードを検索し、Viewに返すメソッドをControllerに追加(Controllerの修正)
- ViewのフォームにHTMLのclass属性とid属性を付与(Viewの修正)
環境
- Rails 4.2.0
- Ruby 2.2.0
- 今回の例として使用しているRailsアプリはrails generate scaffold User name:string email:stringで作成したアプリです。Userモデル(nameカラム、emailカラムを持つ)とUserコントローラのみを持つアプリです。
typeaheadを使用するための準備
typeahead.jsをダウンロード
まず準備として、以下のサイトからtypeahead.jsをダウンロードします。以下URLにアクセスし、右側にある「Download ZIP」というボタンをクリックしてダウンロードします。
twitter/typeahead.js | GitHub
ダウンロードしたZIPファイルを解凍すると、解凍したフォルダ内にdistという名前のフォルダがあります。この中のtypeahead.bundle.min.jsというファイルを使用します。他のファイルとの違いは、上記URLサイトにも書いてあるように、typeahead.js、bloodhound.jsがオートコンプリート実装に必要なjavascript本体ファイルで、それ以外のminが付いているものは圧縮版、bundleが付いているものはtypeahead.js、bloodhound.jsの両方を含むファイルです。したがって、typeahead.bundle.min.jsもしくはtypeahead.bundle.jsのいずれかがあればオートコンプリート機能を実装できます。
今回はtypeahead.bundle.min.jsを使うので、このファイルを各自のRailsディレクトリのapp/assets/javascriptsにコピーすればOKです。
typeahead用のCSSファイルをダウンロード
typeaheadによるオートコンプリートで表示される候補ワードの見栄えを良くするために、以下のURLからtypeahead用のCSSファイルを取得し、app/assets/stylesheetsに配置しておきます。
LESS / CSS code for using typeahead.js with Bootstrap 3 | GitHub以上でtypeaheadを使用する準備は完了です。
typeaheadを動作させるjavascriptファイル作成
Viewでのユーザの入力を検出して、入力ワードをControllerにajax通信で送信し、Controllerから候補ワードを受け取って表示するjavascriptファイルを作成しておきます。このjavascriptファイルの中でtypeaheadを使用します。ここでは作成するファイルをautocomp.jsという名前にし、以下の内容を記述します。
上記の簡単な説明を以下の載せます。
- baseurl = "/typeahead?term=%QUERY"は、ユーザの入力ワードの送信先となるURLになります。後ほど- /typeaheadというURLとユーザの入力ワードを元に候補ワードを返す処理を行うControllerのメソッドを結びつけるルートを- routes.rbに追記します。
- qst1 = { item: 'name' }では、ユーザの入力ワードに対する候補ワードをどのカラムから取得するかを指定しています。すなわち、ここの- nameはUserモデルのnameカラムを指します。
- url1がViewからController宛のパラメータを含むURLになります。このURLに- term、- itemという名前の2つのパラメータを含めます。- termには- %QUERYという値(入力ワードに該当します)、- termには- nameが格納されます。そして後述しますが、これらの値をController側で- params[:term]、- params[:item]で受け取って使うことになります。
- var usernames = new Bloodhound({...では、- usernamesという名前で- bloodoundのオブジェクトを生成しています。- bloodhoundは、typeahead.jsと共に動作する候補ワード表示のためのエンジンです。正直なところ詳細をよくわかっていません。
- jQuery( document ).ready(function( $ ) {...では、ここで指定したHTMLのid属性とclass属性を持つ要素に対してオートコンプリート機能を付与しています。具体的には、- typeaheadという名前のclass属性、- user_nameという名前のid属性を持つ要素にtypeaheadによるオートコンプリート機能を付与しています。また、typeaheadのオプションもここで指定しています。
続いて上記のautocomp.jsの中で各自の環境に合わせて変更必要な部分を以下にまとめておきます。
- 1行目 ここの
- 3行目 ここの
- 11行目 11行目の最後、
- 15行目
- 20行目 9行目で定義した
- 23行目
- 29行目 ~ 30行目
- 33行目 23行目と同様に
/typeaheadは後述するroutes.rbに追加するルートのパスと合わせる必要があります。
nameはUserモデルのカラム名を指します。よって、各自のモデルのカラム名に合わせてください。
d.nameのnameを各自のカラム名に合わせる必要があります。
url1も5行目で定義した名前に合わせる必要があります。
bloodhoundのオブジェクト名にあわせます。
#user_name.typeaheadは後ほどViewファイルのフォーム部分に付与するHTMLのid属性とclass属性です。
'name'はカラム名にあわせます。
#user_name.typeaheadは後ほどViewファイルのフォーム部分に付与するHTMLのid属性とclass属性です。
上記のautocomp.jsにemailのテキストフィールド用にオートコンプリートを行うコードを追加して、autocomp.jsは最終的に以下のようになります。
routes.rbの修正
typeaheadはViewのフォームで入力される度にControllerとajax通信を行い、ユーザの入力ワードをControllerのメソッドに送信します。そしてControllerのメソッドはViewから送信されてきた入力ワードを元に候補ワードをViewに返します。この動作のために、Controllerのメソッドへのルートを追加する必要があります。今回はconfig/routes.rbにusers_controller.rb内のtypeahead_actionへのルートを追記します。typeahead_actionへのパスとして/typeaheadを指定しています。
この後ここで指定したtypeahead_actionという名前のメソッドをControllerに追加します。
Controllerの修正
routes.rbに書いたようにtypeahead_actionという名前のメソッドを追加します。そしてこのメソッドの内容は以下のようにします。
上記のようにjson形式の値をrenderで返すだけのメソッドです。返す値はUserモデルのActive recordで検索した結果になります。
params[:item]は候補ワードの取得先であるカラム名であり、params[:term]はユーザの入力ワードになります。
例として、typeahead_actionが受け取ったparams[:item]、params[:term]がそれぞれ「test」、「name」であった場合は以下の検索結果を返すことになります。
これはnameカラムの値の内、「test」を含む値でユニークなものを返します。このnameカラムの検索結果をViewに返し、候補ワードとして表示することになります。上記のように検索カラム名自体もautocomp.jsからのパラメータで指定できるようにすることで、フォームに合わせた候補ワードを返すことができます。よって、params[:item]にemailという値が格納されていれば、emailカラムから候補ワードを検索しその結果を返します。
なお、RailsのActive Recordのarel_tableの使い方については以下のサイトが参考になりました。ありがとうございました。
whereにSQLの文字列を渡したくない! | Qiita
Viewの修正
次にtypeaheadによるオートコンプリート機能を実装するフォームを修正します。今回は、新規Userを追加するページであるnew.html.erbのname、emailのテキストフィールドにオートコンプリート機能を実装します。すなわち、name、emailのテキストフィールドのHTMLのclass属性とid属性に、上のautocomp.jsの23行目、33行目で指定した名前の属性を付与します。
テキストフィールドにclass属性、id属性を付与
以下のようにname、emailのテキストフィールドそれぞれにtypeaheadという名前のclass属性、nameのテキストフィールドにuser_nameという名前のid属性、emailのテキストフィールドにuser_emailという名前のid属性を付与します。なお、テキストフィールドにform-controlというclass属性も指定していますが、これはBootstarpのCSSを使用するために指定しているだけであり、typeaheadの動作させるために必要なわけではありません。
javascriptを読み込むための記述を追加
new.html.erbでtypeahead.bundle.min.js 、autocomp.js を読み込ませるために以下をnew.html.erbの一番上に追記しておきます。
最終的にnew.html.erbは以下のようになります。
以上でViewの修正は完了です。
動作確認
あとは各自のRailsアプリでオートコンプリートを実装したフォームに何か入力してみて候補ワードが表示されればOKです。
思うように動作しない場合の確認方法
ブラウザのデベロッパツールで確認
以下のように、ChromeやFirefox Developer Editionのデベロッパツールを使えば、javascriptでエラーが発生している場合はすぐに分かります。
個人的にはjavascriptが読み込まれていないことが原因である場合が多かったです。特にapp/assets/javascripts/application.jsの中に//= require_tree .があることが原因だったりします。これについては下記が参考になりました。ありがとうございました。
Rails require_treeを排除し、アセットパイプラインで、コントローラー固有のCSS、JavaScriptを組み込む | Beautiful Ajax
ターミナルで動作確認
Railsをrails s -b 0.0.0.0で起動した場合は、以下のようにオートコンプリートを実装したフォームで入力を行うと、それと同時にtypeaheadによってControllerに入力ワードがajax通信によって送信され、その送信内容などがターミナルに表示されます。もし入力に応じてターミナルに何も表示されない場合はtypeaheadが動作していない可能性が高いです。
上のgifだと見難いですが、ユーザの入力に応じて以下の様な内容がターミナルに表示されると思います。以下はNameのテキストフィールドに「us」と入力した時の表示内容です。
また、ルートが存在しない場合は以下の様にターミナルに表示されるのでわかりやすいです。
以上のように、ターミナルの表示内容を見ると動作しない原因がわかるかもしれません。
おわりに
typeahead.jsを使おうとしたら思ったように動作せず時間を取られたので次回のためにメモしました。なお、日本語対応については以下参考サイトが参考になるかもしれません。
参考サイト様
twitter typeaheadはいろいろ改良されていた | Qiita
関連記事
 公開日:2019/10/04 更新日:2019/10/04 公開日:2019/10/04 更新日:2019/10/04- RailsとSendGridでメール送信処理を実装する- Ruby on RailsからAction Mailerを使用してSendGrid経由でメールを送信する処理を実装したのでその手順をまとめます。 
 公開日:2018/05/30 更新日:2018/05/30 公開日:2018/05/30 更新日:2018/05/30- ブラウザの操作を自動化できるSeleniumをWSLからRubyで使う- フォーム送信や繰り返し行う必要があるブラウザ操作を自動化できるSeleniumをWindows Subsystem for Linux のUbuntuからRubyを用いて使用するための手順をメモします。 
 公開日:2018/05/27 更新日:2018/05/27 公開日:2018/05/27 更新日:2018/05/27- rbenvとruby環境の構築手順- WindowsのWindows Subsystem for LinuxでUbuntuを使いはじめ、その中にrbenvとRuby環境を構築したのでその手順をメモします。なお、UbuntuであればWindows Subsystem for Linux、仮想マシン、純粋なUbuntuのいずれでも同じ手順になります。思っていた以上に簡単に構築できました。 
 公開日:2018/05/06 更新日:2018/05/06 公開日:2018/05/06 更新日:2018/05/06- RubyでGoogleスプレッドシートを読み込み・書き込みする- Googleスプレッドシートを自分で作成したRubyコードから読み込んだり、書き込んだりするためのコードについてまとめます。 
 公開日:2016/01/10 更新日:2016/01/10 公開日:2016/01/10 更新日:2016/01/10- Railsでwickedpdfを使ってPDF出力する- Ruby on RailsでPDF出力させるのに便利なgemはたくさんありますが、htmlをそのままPDF化してくれる「wickedpdf」が一番お手軽で楽でした。wickedpdfの導入手順と使用方法をメモします。 
開発アプリ


