[Rails]jQueryだけで動く連動プルダウン年月日入力フォームを作った。

どうもこんばんは、Chihaと申します。
[初めてデプロイしたアプリに使用した技術](https://qiita.com/chiha-chiha/items/3226bdd83b3d4c974e7e)
の記事を書いたときに、非同期でDBから値を持ってきて選択肢を動く連動プルダウンを実装しましたが、jQueryのみで（ajaxでリクエスト飛ばす等せずに）動く日付入力の連動プルダウンを作ったのでメモ。

## 開発環境
- Ruby on Rails 5.2.2
- Ruby 2.5.1
- jQuery
- haml

## 概要

日付入力フォームの連動プルダウンというのは
<img width="328" alt="スクリーンショット 2019-09-15 23.15.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492745/79709143-e59d-61f1-5944-b2a95fc1d5b9.png">
<img width="321" alt="スクリーンショット 2019-09-15 23.16.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492745/bbf5663c-f34e-df60-58c5-a20d58d2ee2f.png">
<img width="306" alt="スクリーンショット 2019-09-15 23.16.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492745/4c09d559-185e-368b-ce84-4d51ead44e1a.png">
<img width="314" alt="スクリーンショット 2019-09-15 23.17.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492745/6a2b9314-da8f-0ec9-e7f0-0a226eb754e5.png">
こういった感じで、入力された年と月に合わせて日の選択肢を変動させるフォームです。
閏年のせいでコードが長くなる。

月、年が未入力だと何も選択肢が表示されないようにしています。
<img width="321" alt="スクリーンショット 2019-09-15 23.26.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492745/d7f4be9e-19df-622b-d656-f447dd127886.png">

（背景が某フリマアプリのようですが一応僕が作成しました。）

某フリマアプリのクローンを開発してるので似るのは当然かもしれませんが。
本物を触った時、上記の挙動で実装されていたので実装しようと思った次第です。
~~単に書きたかっただけとかじゃないです！見本の仕様です、仕様！~~

## 書いたコード

年と月のselectデータにはActiveHashを使っています。（[これ](https://qiita.com/chiha-chiha/items/3226bdd83b3d4c974e7e)作る時に知るべきでした。とっても便利。）

```haml:registration.html.haml
= fields_for @profile,url: 飛ばすアクション,method: :post do |o|
  //略
  //年のselect
  .select-wrap
    = o.collection_select :birthyear, BirthYear.all,:year,:year,{include_blank: '--'},{class: 'default-select select-year'}
    //ドロップダウン右の矢印アイコン
    %i.select-arrow.fas.fa-chevron-down 
  %span.signup-form__birthday--span 年
  //月のselect
  .select-wrap
    = o.collection_select :birthmonth, Month.all,:value,:value,{include_blank: '--'},{class: 'default-select select-month'}
    %i.select-arrow.fas.fa-chevron-down
  %span.signup-form__birthday--span 月
  //日のselect
  .select-wrap
    = o.select :birthday,{},{},class: 'default-select select-day' do
      //初期値
      %option{value: ""} --
    %i.select-arrow.fas.fa-chevron-down
  %span.signup-form__birthday--span 日
//略
```

ビュー側はこんな感じ。

```javascript:birthday.js
//turbolinks利用中もちゃんと動くように。
$(document).on('turbolinks:load',function(){
  //任意の数字を入れたhtmlを返す処理
  function addHtml(value){
    var html = `<option value=${value}>
                ${value}
                </option>`
    return html;
} 
  //選択肢の一番上のblank用。入れ替える時にフォームの中身を一度リセットするため。
  var blankHtml = `<option>--</option>`
  //valueに与えた数の分だけ選択肢を作る処理
  function addOption(value){
    $("#profile_birthday").children().remove();
    $("#profile_birthday").append(blankHtml);
    //i <= valueの方がよかった気がしてる
    for(var i = 1;i < value + 1;i ++){
      $("#profile_birthday").append(addHtml(i));
    };
  };
  //ここからが入れ替え処理本体
  var changeDateSelect = function(){
    //年・月の入力データをhtmlから吸い出す
    var year = $("#profile_birthyear").val();
    var month = $("#profile_birthmonth").val();
    //閏年判定
    if(year % 100 == 0 && year % 400 != 0 && month == 2){ //閏年じゃない貴重なパターン
      addOption(28); //与えた数の分だけ選択肢を作る
    }else if(year % 4 == 0 && month == 2){ //普通の閏年（？）
      addOption(29);
    }else if(year.length == 0 || month.length == 0){ //どちらかの項目がなければ選択肢をリセットする処理
      $("#profile_birthday").children().remove();
      $("#profile_birthday").append(blankHtml);
      return false;
    }else if(month == 2){　//普通の2月
      addOption(28);
    }else if(month == 4 || month == 6 || month == 9 || month == 11){  //残りは普通の分
      addOption(30);
    }else{
      addOption(31);
    };
  };
  //月または年のselectフォームの値が変化すると動くように設定
  $("#profile_birthmonth").on("change",changeDateSelect);
  $("#profile_birthyear").on("change",changeDateSelect);
});
```
jQuery側はこんな感じ。だいたい2月のせい。
今回は厳密等価比較（===）ではなく、等価比較(==)を使っています。
動かなかっただけです。
（原因をはっきり特定できていません。特定したらコードを修正したいと思います。）

これで年月日の連動プルダウンが実装できました。
粗も多く、簡単なものですが数十分ほどで楽しく書けました。
簡単でも思いついたコードがすんなり動くと嬉しいですね。
~~必要な機能だったのかはわからない。~~

## あとがき
雑な更新となりましたが、トラブル解決より気楽に書けました。
まだまだ学習日数も浅く、粗末な点も多いと思いますが、より良いコード、間違った点などがあればご教授頂けると幸いです。

ではでは。