はじめに
エンジニア転職を目指しRuby on Railsを中心に学習中の初学者です。
ポートフォリオにオートコンプリート機能を実装したので、その備忘録として書き記しておきます。
誤っている箇所や改善点などありましたらご指摘いただけると幸いです。
開発環境
- docker環境
- ruby:3.3.6
- ruby on rails: 7.2
- tailwindcss: 4.0.15
- hotwired/stimulus: 3.2.2
- jsバンドラー(esbuild)を使用
前提
- gem “ransack”を用いてすでに検索機能を実装している状態とします
- Stimulusがすでにインストールされている状態とします
Rails7系ではrails new
を実行した時にデフォルトで、
@hotwired/stimulus
gem "stimulus-rails”
がセットアップされています。
念の為実際に、インストールされているか確認します。
gem "stimulus-rails"
{
"@hotwired/stimulus": "^3.2.2",
"@hotwired/turbo-rails": "^8.0.13",
"@tailwindcss/cli": "^4.1.4",
"tailwindcss": "^4.1.4"
}
1.stimulus-autocompleteをインストールする
オートコンプリート機能を実装するために、まずstimulus-autocomplete
をインストールします。stimulus-autocomplete
の公式githubはこちら
jsバンドラーnode_modules(esbuild、rollup.js、Webpack など)を使用している場合は、npmからパッケージをインストールします。
以下を実行してインストール(docker環境)
$ docker compose exec web yarn add stimulus-autocomplete
上記を実行後、package.json
に"stimulus-autocomplete" が追加されているのを確認します
{
"@hotwired/stimulus": "^3.2.2",
"@hotwired/turbo-rails": "^8.0.13",
"@tailwindcss/cli": "^4.1.4",
"stimulus-autocomplete": "^3.1.0", # 追加される
"tailwindcss": "^4.1.4"
}
2.Autocompleteコントローラを登録する
app/javascript/controllers/application.js
にAutocompleteコントローラーを登録します。
import { Application } from '@hotwired/stimulus'
import { Autocomplete } from 'stimulus-autocomplete' // 追加
const application = Application.start()
application.register('autocomplete', Autocomplete) // 追加
これによりdata-controller="autocomplete"の属性をHTMLに追加することで、インストールしたstimulus-autocomplete
のAutocompleteコントローラが適用される。
3. 検索フォームを編集する
オートコンプリート機能を使用するには、検索フォームに以下の4つの追記が必要です。
<div data-controller="autocomplete" data-autocomplete-url-value="<%= autocomplete_〇〇_path %>" role="combobox">
<%= f.search_field :〇〇_cont, data: { autocomplete_target: 'input' } %>
<%= f.hidden_field :〇〇, data: { autocomplete_target: 'hidden' } %>
<ul class="list-group" data-autocomplete-target="results"></ul>
(1) data: { autocomplete_target: 'input' }を追記
まず検索フォームの<%= f.search_field %>
の中に以下を追記します。
data: { autocomplete_target: 'input' }
autocomplete_target
というカスタムデータ属性を追加することでJavaScriptからこの要素を取得しオートコンプリートの機能を適用できます。
(2) divで囲む
そして<%= f.search_field %>
を以下のdiv
タグで囲みます
<div data-controller="autocomplete" data-autocomplete-url-value="<%= autocomplete_〇〇_path %>" role="combobox">
</div>
そうすると以下のようになります。
<%= search_form_for q, url: url, class: "w-full" do |f| %>
<div data-controller="autocomplete" data-autocomplete-url-value="<%= autocomplete_〇〇_path %>" role="combobox">
<%= f.search_field :〇〇_cont data: { autocomplete_target: "input" } %>
</div>
<%= f.submit "検索" %>
<% end %>
data-autocomplete-url-value="<%= autocomplete_〇〇_path %>"
ではRailsのビューテンプレートでURLを動的に生成してます。つまり〇〇controller の autocomplete アクションが実行され、オートコンプリートの機能が使われる時にそのアクションが呼び出されます。
のちにautocompleteアクションとルーティングを定義します。
(3) 隠しフィールドとulを追加する
<%= f.search_field %>
の下に以下の2つのコードを追加する
<%= f.hidden_field :〇〇, data: { autocomplete_target: 'hidden' } %>
<ul class="list-group" data-autocomplete-target="results"></ul>
<%= f.hidden_field %>
は「隠しフィールド」といい実際のページには表示されません。このフィールドは、ユーザーがオートコンプリートの候補から選んだ「値」を保持するために使われます。
<ul>
には入力内容に応じたオートコンプリートの候補が挿入されます。
最終的にスタイルなどをあてると以下のようになりました。
<%= search_form_for q, url: url do |f| %>
<div class="relative flex rounded-md w-full">
<div data-controller="autocomplete" data-autocomplete-url-value="<%= autocomplete_books_path %>" role="combobox">
<%= f.search_field :title_cont, class: 'flex-grow py-3 px-4 rounded-l-md border focus:outline-none w-[400px] h-[50px]', placeholder: "検索ワード", data: { autocomplete_target: 'input' } %>
<%= f.hidden_field :title, data: { autocomplete_target: 'hidden' } %>
<ul class="list-group absolute w-[400px]" data-autocomplete-target="results"></ul>
</div>
<%= f.submit "検索", class: 'btn bg-[#eed9b6] hover:bg-[#d4b886]' %>
</div>
<% end %>
4. autocompleteアクションを定義する
routes.rb
にautocompleteアクションのルーティングを追記します。
Rails.application.routes.draw do
resources :books do
# 以下を追加する
collection do
get :autocomplete
end
end
end
次にautocompleteアクションを定義します。
class booksController < ApplicationController
# 以下を追加
def autocomplete
@books = Book.where("title like ?", "%#{params[:q]}%")
respond_to do |format|
format.js
end
end
end
これにより検索フォームに文字が入力されると、autocomplete_books_pathにリクエストが行われ、オートコンプリートの結果が取得されるようになります。
5.オートコンプリートの候補表示のviewを作成する
検索フォームの<ul>
タグの中に挿入する用の<li>
<li class="list-group-item" role="option" data-autocomplete-value="〇〇">item</li>
を作成する必要がある。
なのでまずapp/views/〇〇/autocomplete.html.erb
を作成・編集する
<% @books.each do |book| %>
<li class="flex w-full items-center text-sm py-2 px-3 hover:bg-amber-100" role="option" data-autocomplete-value="<%= book.id %>" data-autocomplete-label="<%= book.title %>">
<%= book.title %>
</li>
<% end %>
6.完成
参考記事