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

Rails 5 Auto completeを実装してみた

More than 3 years have passed since last update.

Rails Tutorialが一通り終わったので、返信機能を拡張するオートコンプリート機能を実装してみました。
返信機能に、@ + ユーザー名を入力する際、入力済みの文字列を元にユーザー名の候補のメニューを表示して入力の補完ができる機能を目指しました。

前提

Rails Tutorial 第4版を一通り実装済みで、14章最後の拡張機能で挙げられている6つの機能を実装済みです。
返信機能は、ユーザーテーブルにnicknameを追加し、一意に特定できるようにしています。
Rails 5.1.1にアップデート済みです。
form_forform_withに置き換えています。
ERBはHamlに置き換えています。
テストはminitestの代わりにRSpecを使っています。
E2EテストはTurnipを導入しています。

準備

jQuery UIで実装することにしました。

まず、アセットパイプラインに簡単にjQuery UIを入れられるようになるjquery-ui-railsをGemfileへ。

Gemfile.rb
gem 'jquery-ui-rails'

を追加し、

bundle install

を実行します。

app/assets/javascripts/application.js
//= require jquery-ui
app/assets/stylesheets/application.css
 *= require jquery-ui

を追加します。
これでjQuery UIの準備ができました。

オートコンプリートを実装する

ビューを変更する

マイクロポスト投稿のフォームに変更を加えます。

app/views/shared/_micropost_form.html.haml
= form_with model: @micropost do |f|
  = render 'shared/error_messages', object: f.object
  .field
    = f.text_area :content, placeholder: "Compose new micropost...", id: :micropost_content
  = f.submit "Post", class: "btn btn-primary"
  %span.picture
    = f.file_field :picture, accept: 'image/jpeg,image/gif,image/png'

id: :micropost_contentf.text_areaに追加しました。

JavaScriptを追加する

ビューに画像の大きさを判定するJSのコードがあるので、その後に差し込みます。

app/views/shared/_micropost_form.html.haml
:javascript
  $(function() {
    $('#micropost_content').autocomplete({
      source: "/users/auto_complete.json",
      delay: 500,
      minLength: 2,
      focus: function(event, ui) {
        $("#micropost_content").val(ui.item.nickname);
        return false;
      },
      select: function(event, ui) {
        $('#micropost_content').val(ui.item.nickname);
        return false;
      }
    }).data("ui-autocomplete")._renderItem = function(ul, item) {
      return $("<li>").attr("data-value", item.nickname).data("ui-autocomplete-item", item).append("<a>" + item.nickname + "</a>").appendTo(ul);
    };
  });

source:にリクエスト先を指定します。

autocompleteのオプションについて詳しくは以下を参照してください。
https://api.jqueryui.com/autocomplete/

オートコンプリートした際に何件検索で見つかったか、デフォルトで表示する設定のため、非表示にするCSSを追加します。

app/assets/stylesheets/custom.scss
/* auto-complete */
.ui-helper-hidden-accessible { display:none; }

コントローラーで受け取る

リクエストをコントローラーで受け取り、検索結果をJSONで出力します。

app/controllers/users_controller.rb
class UsersController < ApplicationController
  #...

  def auto_complete
    @users = if params[:term] =~ /(@[^\s]+)\s.*/
             elsif user_nickname = params[:term].match(/(@[^\s]+)/)
               users = User.select('nickname').where('nickname LIKE ? AND activated = ?', "%#{user_nickname[1].to_s[1..-1]}%", true)

               users.map {|user| {nickname: "#@{user.nickname}"} }
             end
    render json: @users.to_json
  end

  #...

end

データベースに@を保存しないようにしているので、検索ではそれを考慮したコードになっています。
params[:term]でフォームに入力された値を取得することができます。

routes.rbに追加する

routes.rb
resources :users do
    member do
      get :following, :followers
    end
    collection do
      get :auto_complete
    end
  end

新しく追加したauto_completeroutes.rbに追加します。

テストについて

以下のリンクを参考にして、メソッドを追加しました。
http://ruby-journal.com/how-to-do-jqueryui-autocomplete-with-capybara-2/

spec/support/utilities.rb
def fill_autocomplete(field, options = {})
  fill_in field, with:options[:with]

  page.execute_script %{ $('##{field}').trigger('focus') }
  page.execute_script %{ $('##{field}').trigger('keydown') }

  selector = %{ul.ui-autocomplete li.ui-menu-item a:contains("#{options[:select]}")}

  expect(page).to have_selector('ul.ui-autocomplete li.ui-menu-item a')
  page.execute_script %{ $('#{selector}').trigger('mouseenter').click() }
end

Turnipでテストを書いているので、以下のようになりました。

app/spec/steps/home_steps.rb
step '検索フォームmicropost_contentに@arと入力するとオートコンプリートで表示され、選択する' do 
  fill_autocomplete 'micropost_content', with: '@ar'
end

step 'Postボタンをクリックする' do
  click_button 'Post'
end

以上で、Rails Tutorialの返信機能を拡張し、オートコンプリート機能を実装できました。

結果

スクリーンショット 2017-06-23 16.17.54.png

こちらでソースコードを公開しています。

参考リンク

swamp09
esm
We build applications which work well and make customers happy.
http://www.esm.co.jp
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