LoginSignup
10
10

More than 5 years have passed since last update.

:remoteを利用してセレクトボックスを動的に描画する

Posted at

【実現出来ること】

  • 親子関係にあるセレクトボックスがあるとき、親のセレクトボックスの値で、子のセレクトボックスの選択肢を動的に制御する
  • railsの"remote"の仕組みを利用する

https://gyazo.com/9a21c3e3b6c2b1656a8fb9903507b9cd

【やり方】

環境

  • rails 5

モデル・テーブルデータ

  • usersテーブルはid, color_id, vegetable_idカラムを持つ

    id name color_id vegetable_id
  • colorsテーブルはid, nameカラムを持つ

    id name
    1
    2
    3
  • vegetablesテーブルはid, name, color_idカラムを持つ

    id name color_id
    1 キャベツ 1
    2 ほうれん草 1
    3 小松菜 1
    4 バナナ 2
    5 レモン 2
    6 トウモロコシ 2
    7 人参 3
    8 トマト 3
    9 唐辛子 3

コード

  • ルーティング
config/routes.rb
Rails.application.routes.draw do
  resources :users

  # selectからremote: trueでpostされるデータを受け取り、getで描画するための準備
  match 'dynamic_vegetable', to: 'users#dynamic_vegetable', via: [:get, :post]
end
  • view
app/views/users/new.html.erb
<%= form_for(@user, url: {action: :create}) do |f| %>

<!-- remote: trueを追加することでajaxでparams[:user][color_id]をpostできる -->
<div>
  <%= f.select :color_id, options_from_collection_for_select( @color, :id, :name),
  {prompt: '野菜の色を選択'}, {data: {remote: true, url: url_for(action: :dynamic_vegetable)}} %>
</div>

<!-- 色を選択するとここに動的にセレクトボックスが描画される -->
<div id="vegetable-select">
  野菜
</div>

<%= f.submit '登録', name: 'commit' %>

<% end %>

  • コントローラ
app/controllers/users_controller.rb
def new
  @user = User.new
  @color = Color.all
end

def dynamic_vegetable
  # vegetablesをcolor_idで絞り込んで取得する。
  @vegetable = Vegetable.where(color_id: params[:user][:color_id])
end
  • セレクトボックスを動的に描画するためのview
app/views/users/dynamic_vegetable.js.erb
// 受け取った@vegetableを元にselectボックスを描画する
$('#vegetable-select').html(
  "<%= j(select :user, :vegetable_id, options_from_collection_for_select(@vegetable, :id, :name)) %>"
);

解説

  • viewでselectにremote: trueを設定する。これにより、選択した時にparams[:user][:color_id]が指定のurlにpostされる。このparamsを後のコントローラのアクションで使うことが出来る。
  • ajaxのpostでを受け取ってアクションに流すためのルーティングを追加する。
    • 「 match 'dynamic_vegetable', to: 'users#dynamic_vegetable', via: [:get, :post]」
  • コントローラに、postでうけとったparamsのcolor_idに基づいて@vegetableを取得するアクションを追加する
  • js.erbファイルを用意して、@vegetableに基づいてセレクトボックスを描画するコードを書く。セレクタで指定した箇所のみが部分的に更新され描画される。

メモ

  • これぐらいのデータ数であれば、Color.all, Vegetable.allを一度のリクエストで全部JSONで渡し、ローカルでjavascriptを書いた方が早い
  • データ数が多量(1000以上?)なら、ajaxで都度リクエストした方がよい。
  • remote使わずに、javascriptでajax書いて、JSONを返すアクションを書いて実装することは可能だけど、個人的には、今回紹介した様に、remoteで書いた方がコードの見通しが良くなる気がするので好き。
10
10
0

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
10
10