Help us understand the problem. What is going on with this article?

jQueryUI オートコンプリート機能の実装

More than 1 year has passed since last update.

やりたいこと

USERSテーブル内のnameをtext_fieldから入力する際に、すでに入力済みのものが候補として出て来るようにする

環境

Rails 5.1.5
Ruby ruby 2.3.5p376

基本の流れ

参考サイトを元にjQuery UIで実装
とはいえ初心者過ぎてめちゃめちゃ悩んだので、実装の手順を追って段階的に記載していくことにします。

  1. gemインストール
  2. jQuery UIで予め用意した配列からサジェストを実装
  3. JSONファイルの出力と確認
  4. JSONのjQuery UIへの設定
  5. サジェストの実装

jQuery UIのgemインストール

rails g scaffold user name

scaffoldしたデータでお試し実装。通常通り新規のユーザー入力ができることを確認の上、以下へ

Gemfile
gem 'jquery-ui-rails'
gem 'bootstrap-sass'
gem 'jquery-rails'
$ bundle

jQueryの記述

まずはシンプルな形から。
無事RUN RONでサジェストがきく。
RUまで打つとRUNだけ候補に残る。
そもそもよく使うものがいくつかあって、その上で自由入力も、ならば此れでもいい気がする。

views/users/_form.html.erb
<%= form_with(model: user, local: true) do |form| %>
<!--バリデーションエラーの表示コード割愛-->
  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name, id: :user_name %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

  <script>
  $( function() {
    var names = ['RON','RUN'];
    $( "#user_name" ).autocomplete({
      autoFocus: true,
      source: names,
      minLength: 0,
    });
  });
  </script>

JSONファイルの出力

すでに登録済みのDBから候補を表示させたいので、
一度出力したい内容をcontrollerで指定して出力、それを参照先とする。
一度便宜的にnewアクションに一緒にjsonファイルの出力埋め込んでみる

controller.rb
def new
 @user = User.new

 users = User.all
 users = users.map(&:name)
 render json: users.to_jsonend

  respond_to do |format|
      format.html
      format.json { render json: users.to_json }
  end

User.allで全てのユーザーを呼び出して、名前部分だけ取り出して配列化、それをJSONファイルとして受け渡し
respond_to ~ の記述がないと、newにアクセスしたときにjson画面に推移してしまうので、
末尾にjsonを指定したときだけjson画面に行けるようにアクセスしたURLのフォーマットに従って分岐させる

/users/new (既定値) → html
/users/new.json → json

new.jsonにアクセスしてみると、作成されたjsonファイルはこんな感じだった

new.json
[
        "sasuke",
        "akura",
        "山田",
]

公式によると、value(選択決定後の表示)とlabel(サジェストしてる時の表示)の記述または配列がフォロー対象の模様

JSONのjQuery UIへの設定

views/users/_form.html.erb
  <script>
  $( function() {
    $( "#user_name" ).autocomplete({
      autoFocus: true,
      source: “/users/new.json”,
      minLength: 0,
    });
  });
  </script>

これで、候補一覧はでてくるが何を打っても同じものが出てくる状態になる。
参照はできているが絞込ができない

サジェストの実装

コントローラーとルーティングの書き換え
新規にJSONファイル作成用のメソッドを作成する。

users_controller.rb
  def auto_complete
    users = User.select(:name).where("name like '%" + params[:term] + "%'").order(:name)
    users = users.map(&:name)
    render json: users.to_json
  end

このURLにアクセスするためのルーティングも指定する

route.rb
  resources :users do
    collection do 
      get users/auto_complete
    end
  end

jQueryで指定しているフォーム(この例だと text_filed (id=“user_name”))に入力した内容はminLengthなどの他の項目を満たす場合に、params[:term]としてsource先に定期的(初期値だと300ミリ秒)に送付されているため、それにともなって語句の絞込もおこなわれる模様。

views/users/_form.html.erb
  <script>
  $( function() {
    $( "#user_name" ).autocomplete({
      autoFocus: true,
      source: "/users/auto_complete_name.json",
      minLength: 1,
    });
  });
  </script>

ハマったポイント

  • sourceに記載する相対URLの頭の/が抜けていて指定ができなかった。

    • 記載は source: “/users/auto_complete.json”  など、頭は必ず/から。
  • controllerで配列化したものをViewに持ってきてそれを候補として使えない

    • Viewにおいた地点でダブルクォーテーションが文字列化してしまいうまく動かない
  • JSONファイルを指定しているが、サジェストがきかない

    • 公式に記載があった。絞込は外部ファイルの場合できないようなので、params[:term]を使って記載するべし

感想

何はなくとも公式読んだほうがいい…

参考

公式:
https://api.jqueryui.com/autocomplete/#option-delay

Rails 5 Auto completeを実装してみた
https://qiita.com/swamp09/items/6fb852489b4dc3acfbdd

Ruby on Rails - Railscasts PRO #102 Auto-Complete Association (revised)
https://www.youtube.com/watch?v=M7yhPlIehFA

JS形式のレスポンスと remote: true を使う
https://qiita.com/hc_isobe/items/a29860d3e86a6bc5fd3e

JQueryで自動補完
https://qiita.com/yu_0105/items/20c4f52e71020af42e7b

AutoCompleteウィジェットで候補リストをサーバーサイドから取得するには?
https://www.buildinsider.net/web/jqueryuiref/0019

RailsでAjax基本形(Scaffoldで学ぶ)
https://qiita.com/mm36/items/684f36f22e79d0a27ae9

jqueryのメモ
https://elearn.jp/jmemo/tag/form

obmshk
Webエンジニア2年目
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away