railsで期間をセレクトボックスで登録する

目次

マーケター、エンジニアを月1時間からジョインできるプラットフォーム

airteamは月1時間からマーケターやエンジニアに相談できるプラットフォーム。 雇うのはハードル高いけどプロをチームに入れたい。そんな経営者のためのサービスです。 相談にのる方も募集しています。

タスクなしだから月一時間からジョイン可能

作業はなくオンライン相談メイン。 月1時間からさっと経験者に継続的に相談できます。

多様な経験者を雇用するより何倍も早くチームに

あらゆるジャンルの経験者がいるので あなたのチームのノウハウの選択肢が広がります。

NDAはすでに締結済み、契約もスムーズ

契約の煩雑なやりとりはなく、NDAはすでに締結済み、書面のやりとりはありません。

今回はrailsで期間をセレクトボックスで登録していきます。いや、input type=monthがあるじゃんとツッコミがきそうですが、あまりデザイン的にカッコよくなかったのと変えようと思うとjavascriptを結構頑張らないといけないのでセレクトボックスで選択できるようにしました。

今回作るもの

下記のものを作っていきます。

  • rails
  • 期間を開始年月から終了年月で入力
  • データの方はdate型
  • 開始年月は終了年月よりも前でないと弾く
  • 年月がちゃんとペアで入っていないといけない

メリデメ

input type=”month”を使う

通常で考えると年月をdate型で登録したいという場合はinput type=”month”を使う。

https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/month

ただ、あまりデザイン的に好きじゃないのとデザインを変えようと思うとjavascriptを結構頑張らないといけない。デザイン気にしない場合はこれを使うのが最もバグが少なく、楽。

セレクトボックスを使う

セレクトボックスで登録する場合、下記が面倒。

  • 年月どちらかけた際の挙動を指定
  • 年月を別のセレクトボックスでparamsを送り、date型に変換し、繋げないといけない

上記デメリットがあるがデザインを変更できる方を優先したい場合はセレクトボックス。

実装

formの実装

<%= form_with model: @career, local: true do |form| %>
          <div>
            <label class="form_label">
              期間
            </label>
            <div class="flex">
              <div class="mb-4 form_period flex">
                <div class="select year_select">
                  <%= form.select :period_start_year, options_for_select(((Time.now.year - 50)..Time.now.year).reverse_each), include_blank: "年" %>
                  <div class="select__arrow"></div>
                </div>
                <div class="select month_select">
                  <%= form.select :period_start_month, [["1月","01"],["2月","02"],["3月","03"],["4月","04"],["5月","05"],["6月","06"],["7月","07"],["8月","08"],["9月","09"],["10月","10"],["11月","11"],["12月","12"]], include_blank: "月" %>
                  <div class="select__arrow"></div>
                </div>
              </div>
              <div class="mb-8 form_period flex">
                <div class="form_period_end_text">
                  〜
                </div>
                <div class="select year_select">
                  <%= form.select :period_end_year, options_for_select(((Time.now.year - 50)..Time.now.year).reverse_each), include_blank: "年" %>
                  <div class="select__arrow"></div>
                </div>
                <div class="select month_select">
                  <%= form.select :period_end_month, [["1月","01"],["2月","02"],["3月","03"],["4月","04"],["5月","05"],["6月","06"],["7月","07"],["8月","08"],["9月","09"],["10月","10"],["11月","11"],["12月","12"]], include_blank: "月" %>
                  <div class="select__arrow"></div>
                </div>
              </div>
            </div>
          </div>
          <div class="overflow-hidden">
            <%= form.submit "登録" %>
          </div>
          <% end %>

selectタグで生成する。年を一つ一つオプション書くのは面倒なので

<%= form.select :period_end_year, options_for_select(((Time.now.year - 50)..Time.now.year).reverse_each), include_blank: "年" %>

上記で50年分生成する。

include_blankで初期値を設定。

controller1:年月揃ったら登録

年だけ入ってて月が入っていないのに入力されると面倒なので下記で弾く

    if params[:career][:period_start_year].present? && params[:career][:period_start_month].present? && params[:career][:period_end_year].present? && params[:career][:period_end_month].present?
      period_start = Date.new(params[:career][:period_start_year].to_i, params[:career][:period_start_month].to_i)
      period_end = Date.new(params[:career][:period_end_year].to_i, params[:career][:period_end_month].to_i)
    else
      flash[:alert] = "開始、完了の年月を全て入力してください。"
      redirect_back(fallback_location: root_path) and return
    end

開始だけ、完了だけも困るので全部揃った場合だけ登録できるようにする。modelで弾くかcontrollerで弾くかは難しいところだが、date型への変更の前に弾いた方が判定が楽だったので今回はcontrollerで弾く。

period_start = Date.new(params[:career][:period_start_year].to_i, params[:career][:period_start_month].to_i)

上記でdate型に変換。というよりdate型をnewで生成する。

気をつけないといけないのが、こういったcontrollerで弾きたい場合にredirectをかけるなら下記のようにand returnを書かないとダブルレンダリングになる。これはredirectが予約されている状態になるので後ろにさらにredirectを書いていると二重になってしまうため。

redirect_back(fallback_location: root_path) and return

controller2:開始年月が終了年月よりも後ろだと弾く

開始年月が終了年月よりも後ろだと弾く処理はcontrollerでのdate型への変換と関係ないのでmodelで弾く。下記をmodelに記述。

  validate :period_end_after_period_start

  private

  def period_end_after_period_start
    if period_end.present? && period_start.present? && period_end < period_start
      errors.add(:base, "終了月は開始月より後にしてください")
    end
  end

完成

上記でセレクトボックスの開始年月、完了年月の入力が完了。