프론트엔드 설정
동적 종속 선택 박스 구현을 위해 TomSelect 라이브러리를 통합하는 것이 첫 단계입니다. Rails 7+ 환경에서는 importmap
을 통해 JavaScript 라이브러리를 관리하는 것이 권장됩니다.
-
TomSelect 설치 및 설정:
bin/importmap pin tom-select
명령어를 사용하여 TomSelect를 importmap에 추가하고,config/importmap.rb
파일에 CDN 경로를 명시합니다. CSS 파일은app/views/layouts/application.html.erb
에 직접 링크하여 전역적으로 적용합니다.ruby # config/importmap.rb pin "tom-select", to: "https://cdn.jsdelivr.net/npm/tom-select@2.4.3/+esm"
```html
```
Stimulus 컨트롤러 구현
두 가지 Stimulus 컨트롤러가 필요합니다. 하나는 일반 TomSelect 초기화를 위한 것이고, 다른 하나는 종속 선택 박스 로직을 처리합니다.
-
select_controller.js
: 모든data-controller="select"
요소에 TomSelect를 초기화하는 기본적인 컨트롤러입니다. 연결 시 TomSelect 인스턴스를 생성하고, 연결 해제 시 인스턴스를 파괴하여 메모리 누수를 방지합니다.```javascript // app/javascript/controllers/select_controller.js import { Controller } from “@hotwired/stimulus” import TomSelect from “tom-select”
export default class extends Controller { connect() { new TomSelect(this.element) } disconnect() { if (this.element.tomselect) { this.element.tomselect.destroy() } } } ```
-
select_with_dependent_controller.js
: 이 컨트롤러는 종속 선택 박스의 핵심 로직을 담당합니다.static values
를 사용하여 AJAX 요청에 필요한 URL, 파라미터 이름, 대상 요소 ID, 그리고 JSON 응답에서 값을 추출할 키를 설정합니다.update
메서드는 상위 선택 박스의change
이벤트에 의해 트리거됩니다. 이 메서드는 현재 선택된 값을 기반으로 AJAX 요청을 생성하고, 서버로부터 받은 JSON 데이터를 파싱하여 하위 선택 박스의 옵션을 동적으로 업데이트합니다. TomSelect가 적용된 경우clearOptions
,addOption
,refreshOptions
메서드를 사용하여 옵션을 조작하며, 일반<select>
요소의 경우innerHTML
을 직접 조작합니다.javascript // app/javascript/controllers/select_with_dependent_controller.js // ... (생략) export default class extends Controller { static values = { url: String, param: "id", target: String, target_name: "name", target_value: "id" } connect() { new TomSelect(this.element) } disconnect() { /* ... */ } update() { const url = new URL(this.urlValue, window.location.origin) url.searchParams.set(this.paramValue, this.element.value) fetch(url, { headers: { Accept: "application/json" } }) .then(response => response.json()) .then(data => { const target = document.getElementById(this.targetValue) if (target && target.tomselect) { target.tomselect.clearOptions() data.forEach(option => { target.tomselect.addOption({ value: option[this.targetValueValue], text: option[this.targetNameValue] }) }) target.tomselect.refreshOptions(false) } // ... (일반 select fallback) }) } }
Rails 백엔드 구성
백엔드는 AJAX 요청에 응답하여 필터링된 데이터를 JSON 형태로 제공하는 역할을 합니다.
-
라우팅 설정:
config/routes.rb
파일에searches/products
리소스에 대한 라우트를 정의하여index
액션을 통해 제품 목록을 가져올 수 있도록 합니다.ruby # config/routes.rb namespace :searches do resources :products, only: :index end
-
컨트롤러 구현:
app/controllers/searches/products_controller.rb
에서index
액션은params[:company_id]
를 기반으로 제품을 필터링하고, 그 결과를 JSON 형태로 렌더링합니다.filter_by_company
private 메서드는company_id
파라미터의 유무에 따라 필터링 조건을 동적으로 생성합니다.ruby # app/controllers/searches/products_controller.rb module Searches class ProductsController < ApplicationController def index @products = Product.where(filter_by_company) render json: @products.to_json end private def filter_by_company return {} unless params[:company_id].present? { company_id: params[:company_id] } end end end
뷰 통합
app/views/welcome/index.html.erb
파일에서 두 개의 선택 박스를 정의하고 Stimulus 컨트롤러와 연결합니다.
- 상위 선택 박스:
company
선택 박스에는data-controller="select-with-dependent"
와data-action="change->select-with-dependent#update"
를 적용하여 변경 시select_with_dependent
컨트롤러의update
메서드가 호출되도록 합니다. 또한,data-select-with-dependent-url-value
,data-select-with-dependent-target-value
,data-select-with-dependent-param-value
속성을 통해 컨트롤러에 필요한 정보를 전달합니다. - 하위 선택 박스:
product
선택 박스에는data-controller="select"
를 적용하여 기본적인 TomSelect 기능을 활성화하고,id: :product_select
를 부여하여 상위 컨트롤러가 이 요소를 식별할 수 있도록 합니다.