【Rails】Ajaxでセレクトボックスの内容を動的に変更する
こんばんは!1週に一回記事更新しますわ〜とか言っておきながら1ヶ月ぶりの更新です…笑
今回の内容は2つのセレクトボックスがあった時に片方のセレクトボックスが変更されたら、もう片方のセレクトボックスで選択できる内容が動的に変更されると言った内容です!
概要だけだと何言ってるかわけわからないと思うので例を挙げると、県と市区町村が選択できるセレクトボックスがそれぞれ存在する時に、県を選択したら市区町村のセレクトボックスの方が選択された県に存在する市区町村が選択肢になるようなイメージです。
どう作ればいいかわからない状態から作ったのでかなり時間がかかったので備忘録がてら書いときます
想定
とりあえずテーブル構造はこんな感じ
prefecturesとcitesとマスタテーブルとしていて存在していて、そんでprofilesに住んでいる県と市区町村が登録されるみたいな想定
ビュー
new.html.erb
<%= form_for(@profile) do |f| %> <% if @profile.errors.any? %> <div id="error_explanation"> <ul> <% @profile.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> </div> <% end %> <div class="prefecture-area"> <%= label :prefecture_id %><br> <%= collection_select :profile, :prefecture_id, Prefecture.all, :id, :name %> </div> <div class="city-area"> <%= render partial: 'select_city', locals: {prefecture_id: Prefecture.first.id} %> </div> <% end %>
_select_city.html.erb
<%= label :profile, :city_id %><br> <%= collection_select :profile, :city_id, Prefecture.where(prefecture_id: prefecture_id), :id, :city_name %>
動的にセレクトボックスを入れ替えるcity_idの方はselect_city
という名前でパーシャル化。
パーシャル化することでAjaxで返ってくる結果をレンダリングしやすくしとく。
コントローラ
class ProfilesController < ApplicationController def new @profile = Profile.new end # Ajax処理を行う処理 def get_cities render partial: 'select_city', locals: {prefecture_id: params[:prefecture_id]} end end
セレクトボックスを動的に変える処理をget_cities
というアクションで受け取る。
Ajaxでこのアクションを呼ぶ。
ルーティングは以下の感じで
Rails.application.routes.draw do resources :profiles, only: :new do collection do get 'get_cities' # /profiles/get_cities end end end
モデル
今回の記事の本質からは外れるので割愛します。
だいたいテーブル構造で想像してください。
Coffee Script
セレクトボックスを動的に変えるのはAjaxを使って実現するためcoffeeやjavascriptが肝になる。
ここがいまいちわかっていなかったので色々詰まっていた…
$(document).on 'change', '#profile_prefecture_id', -> $.ajax( type: 'GET' url: '/profiles/get_cities' data: { prefecture_id: $(this).val() } ).done (data) -> $('.city-area').html(data)
$(document).on 'change', '#profile_prefecture_id'
この処理でprefecture_idのセレクトボックスが変更されたことを検知する。
profile_prefecture_id
はcorrection_selectで自動生成されるid。correction_selectというよりForm系のヘルパーで生成される。
$.ajax( type: 'GET' url: '/profiles/get_cities' data: { prefecture_id: $(this).val() }
ここでAjaxの通信を開始している。type
にメソッド、url
に呼び出すアクションのパス、data
にコントローラに渡す値を設定する。
今回のdata
はセレクトボックスで選択された値をparams
にprefecture_id
として乗せる。
done(data)
でアクションの結果を受け取る。今回のアクションはprofiles
コントローラのget_cities
アクションでget_cities
の中身はrender partial: 'select_city', locals: {prefecture_id: prefecture_id}
なので_select_city.html.erb
をレンダリングした結果を受け取る。
アクションの処理結果はdata
に格納されている。
ここのdata
は$.ajax
でコントローラに渡したdata
とは別もんな気がするので注意。
$('.city-area').html(data)
でレンダリングされたHTMLソースを<div class="city-area">
内に差し込むことでセレクトボックスを入れ替える。
ここまでやることでセレクトボックスの入れ替えが実現できました!
いざ記事にしてみると大して難しいことはやっていないのだけど、初めて実装する機能などはやはり難易度が高いように感じてしまう…。
こうやって色々試して、ブログなんかで知識を蓄積して慣れていくしかないですかね…。
うわぁ、がんばろう