LoginSignup
49
48

More than 5 years have passed since last update.

Rails 5 Auto completeを実装してみた

Last updated at Posted at 2017-06-23

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

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

参考リンク

49
48
3

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
49
48