railsでサジェスト機能を実装した時のメモ🍣
autocomplete系のgemが軒並みメンテされていなかったので、jquery-uiで実装していきます。
動作環境
rails 5.2.2.1
jquery-ui-rails 6.0.1
やること
company
属性を持つUser
というモデルを想定し、
User作成画面でcompany
のテキストフィールドに入力した際、
既にDBに存在するデータをもとに候補をサジェストする機能を実装します😎
Gemfile
Gemfileに下記を追加しbundle install
gem 'jquery-ui-rails'
bundle install
application.js
下記を追加
//= require jquery-ui/widgets/autocomplete
application.scss
下記追加
@import "jquery-ui/autocomplete";
@import "jquery-ui/theme";
@import "jquery-ui/menu";
筆者環境だと、theme、menuを外すと表示が崩れました🤔
routes.rb
サジェストの配列を返すルートを追加します。
resources :users do
get '/autocomplete_company/:company', on: :collection, action: :autocomplete_company
end
モデル
前方一致検索のscopeを追加します。
# 前方一致検索
scope :by_company_like, lambda { |company|
where('company LIKE :value', { value: "#{sanitize_sql_like(company)}%"})
}
コントローラー
サジェストの候補を返すaction追加
受け取ったパラメータをもとにサジェストしたい文字列の配列を返すようにします。
def autocomplete_company
# params[:company]の値でUser.companyを前方一致検索、company列だけ取り出し、nilと空文字を取り除いた配列
companies = User.by_company_like(autocomplete_params[:company]).pluck(:company).reject(&:blank?)
render json: companies
# レスポンスの例: ["てすと1会社","てすと2会社","てすと3会社"]
end
private
def autocomplete_params
params.permit(:company)
end
ビュー
autocompleteのsourceに
サジェスト候補の配列を取得する関数をセット。
= form_with(model: @user, local: true) do |form|
.form-group
= form.label :company
= form.text_field :company
/ id='user_company'で生成される
javascript:
$(function() {
const dataList = function(request, response) {
$.ajax({
url: '/users/autocomplete_company/' + request.term,
dataType: 'json',
type: 'GET',
cache: true,
success: function(data) {
response(data);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
response(['']);
}
});
}
// #user_companyの部分は必要に応じてidなり指定してください
$('#user_company').autocomplete({
source: dataList,
autoFocus: true, // 自動的に先頭の項目にフォーカスするか
delay: 300, // 入力してからサジェストが動くまでの時間(ms)
minLength: 2 // 2文字入力しないとサジェストが動かない
})
});
テキストフィールドの内容に応じて、動的に内容を変える必要がなければ
dataListにサジェストしたい文字列の配列を直接入れればOKです!
javascript:
$(function() {
const dataList = ["こうほ1","こうほ2"];
});
まとめ
jquery-uiを使って、サジェスト機能を実装しました。
今回は説明のため、Viewに直接javascriptを書いてますが
別ファイルにしたり、ヘルパーを切り出したりすると良いと思われます☺️
間違っているところがあればご指摘ください!