【Rails】JSでプルダウンの選択肢を変更する

勉強のため、メルカリのクローンアプリ作成中です。
商品出品ページに関する備忘録です。

# 何がしたいか？
- メルカリ本家の商品出品ページと同様、カテゴリーを選択すると、サイズのプルダウンが表示される。
- サイズテーブルは作成せず、activehashで実装。
- 選択したカテゴリーに応じて、サイズの選択肢を変更。
- 選択したカテゴリーにサイズの分類がない場合は、サイズボックスは表示せず、自動的に 該当なし を選択。

# 最終ゴール
![Alt text](https://gyazo.com/5f0871892006a162d65b634066c07ca2/raw)
# 考え方
カテゴリーテーブルとサイズテーブル間に、紐付けるためのテーブルを新たに作成することも考えましたが、今回は、データ量が多くないので、簡易的にJSで実装する方法を考えてみました。
※ 本来は前者がセオリーだと思うので、あまり良い方法ではないかもしれません。

- サイズの全データを取得し、collection_selectで表示
- カテゴリー選択によりイベントを発火させ、カテゴリーidを取得し、カテゴリーidに応じて、不要な選択肢を`display:none;`で隠す。

# 実装の手順
activehashを導入し、sizeモデルを作成。
※ activehashの導入まで：[Qiita【Rails】初めてのactive_hash](https://qiita.com/manbolila/items/2278baf0c25bc80d0726)

```ruby:size.rb
class Size < ActiveHash::Base
  self.data = [
    {id: 1, name: 'XXS以下'}, 
    {id: 2, name: 'XS(SS)'}, 
    {id: 3, name: 'S'},
    {id: 4, name: 'M'}, 
    {id: 5, name: 'L'}, 
    {id: 6, name: 'XL(LL)'}, 
    {id: 7, name: '2XL(3L)'},
    {id: 8, name: '3XL(4L)'}, 
    {id: 9, name: '4XL(5L)以上'},
    {id: 10, name: 'FREE SIZE'},

    {id: 11, name: '20cm以下'}, 
    {id: 12, name: '20.5cm'}, 
    {id: 13, name: '21cm'},
    {id: 14, name: '21.5cm'}, 
    {id: 15, name: '22cm'}, 
    {id: 16, name: '22.5cm'},
    {id: 17, name: '23cm'}, 
    {id: 18, name: '23.5cm'}, 
    {id: 19, name: '24cm'},
    {id: 20, name: '24.5cm'}, 
    {id: 21, name: '25cm'}, 
    {id: 22, name: '25.5cm'},
    {id: 23, name: '26cm'}, 
    {id: 24, name: '26.5cm'}, 
    {id: 25, name: '27cm'},
    {id: 26, name: '27.5cm以上'},
    
    {id: 27, name: '60cm'}, 
    {id: 28, name: '70cm'}, 
    {id: 29, name: '80cm'},
    {id: 30, name: '90cm'}, 
    {id: 31, name: '95cm'},
    {id: 32, name: '100cm'}, 
    {id: 33, name: '110cm'}, 
    {id: 34, name: '120cm'},
    {id: 35, name: '130cm'}, 
    {id: 36, name: '140cm'}, 
    {id: 37, name: '150cm'},
    {id: 38, name: '160cm'},

    {id: 39, name: '10.5cm以下'}, 
    {id: 40, name: '11cm・11.5cm'}, 
    {id: 41, name: '12cm・12.5cm'},
    {id: 42, name: '13cm・13.5cm'}, 
    {id: 43, name: '14cm・14.5cm'}, 
    {id: 44, name: '15cm・15.5cm'},
    {id: 45, name: '16cm・16.5cm'}, 
    {id: 46, name: '17cm以上'},
       :
    {id: 65, name: '該当なし'}
  ]
end
```
ビューに、selectボックスを作成（※DBからデータ取得するため、selectではなく、collection_selectを使用）。
cssで`display:none;`の状態にしておき、カテゴリー選択により、表示させる。

```haml:form.html.haml
= form_for @item, local: true do |f|
     :
  #size_box  
  %label.item_input__body__label
    サイズ
    %span.required 必須    
  .pulldown#size_selectbox
    = f.collection_select :size_id, Size.all, :id, :name, {include_blank: "選択してください"}, {class: "size_box"}
    = icon('fa', 'chevron-down')
     :
```
jQuery実装。
カテゴリー選択で、イベント発火させる。

```JS:item.js
$(document).on('change', '#grandchildren_box', function() {
  //選択肢たカテゴリーid情報を取得
  let grandchildId = $('#grandchildren_category').val();
  //カテゴリーが初期値でない場合
  if (grandchildId != "") {
    $('.size_box').val('');
    $('.size_box option').css('display', 'block');
    $('#size_box').css('display', 'block');

    //カテゴリー選択によって、サイズボックスの選択肢を変更
    if (grandchildId <= 66||grandchildId >= 78 && grandchildId <= 80||grandchildId >= 174 && grandchildId <= 176||grandchildId >= 178 && grandchildId <= 181||grandchildId >= 186 && grandchildId <= 194||grandchildId >= 200 && grandchildId <= 247||grandchildId >= 270 && grandchildId <= 274||grandchildId >= 330 && grandchildId <= 332||grandchildId >= 340 && grandchildId <= 342) {
      $('.size_box option[value]').each(function(i) {
        if (i>=11) {
          $('.size_box option[value = ' +(i)+ ']').css('display', 'none');
        }
      });
    } else if (grandchildId >= 67 && grandchildId <= 77||grandchildId >= 248 && grandchildId <= 256) {
      $('.size_box option[value]').each(function(i) {
        if (i>=1&&i<11 || i>=27) {
          $('.size_box option[value = ' +(i)+ ']').css('display', 'none');
        }
      });
                    :
                    :
    //サイズの分類がないカテゴリーが選択された時
    } else {
      $('#size_box').css('display', 'none');
      $('.size_box').val(65);
    }
  //カテゴリーが初期値の場合
  } else {
    $('.size_box').val('');
    $('#size_box').css('display', 'none');
  }
});
```