Help us understand the problem. What is going on with this article?

【Rails】date_selectタグの使い方メモ

最初に

根性でフロント作成〜サーバサイド作成までdate_selectタグで乗り切った!
ので、自分を労わる意味で備忘録を書きます。

間違っているなどあれば、指摘をいただけると嬉しいです。

date_selectタグ

超簡単に年月日の入力フォームが作れます。
ただ、色々癖があります。

パターン① 生年月日

Image from Gyazo

sample.html.haml
  != sprintf(f.date_select(:birthday, prefix:'birthday',with_css_classes:'XXXXX', prompt:"--",use_month_numbers:true, start_year:Time.now.year, end_year:1900, date_separator:'%s'),'年','月')+'日'

パターン② クレジットカードの有効期限

Image from Gyazo

sample.html.haml
      != sprintf(f.date_select(:expiration_date,with_css_classes:'XXXXX', order:[:month,:year,:day], use_month_numbers:true, discard_day:true, start_year:Time.now.year-2000, end_year:Time.now.year-2000+10, date_separator:'%s'),'月') + '年'

※payjpに送るときは2000足すか、文字列として頭に'20'を足さないとダメな所が注意です!

利用オプションの解説

オプション 概要 書き方例
with_css_class 年月日それぞれでCSSを当てたい場合に利用。実際のCSSはyear,month,dayで指定が可能になる with_css_classes:'任意のクラス名'
order 年月日の順番を変えたい場合に利用。表示させない場合でも必ず年月日全部書く必要あり order:[:month,:year,:day]
use_month_numbers 月の表示を数字にしたい場合に利用 use_month_numbers:true
discard_year 年の表示を消したいときに利用 discard_year:true
discard_month 月の表示を消したいときに利用 discard_month:true
discard_day 日の表示を消したいときに利用 discard_day:true
disabled プルダウンを選択不可にする disabled:true
prompt 指定データがない場合の初期値表示(一番上の表示)に利用 prompt:"--"
prompt:"選択してください"
selected 指定データがある場合の指定に利用 selected:Time.now(Date型変数ならOK)
start_year プルダウンの一番上に来る年数を指定 start_year:Time.now.year
start_year:2019
end_year プルダウンの一番下に来る年数を指定 end_year:Time.now.year-10
end_year:1900
date_separator 年月日のフォームを分けた場合の中間に表示する値を指定。 date_separator:'%s'
date_separator:'/'

date_separatorの補足

date_separatorは、フォーム間にのみ文字を挿入してくれます。
ただ、日本語で年月日を指定したい場合はsprintfと組み合わせないと上手く表示ができません。
そこの理解に苦労したので補足。
※yyyy/mm/ddと描きたいだけなら、date_separator:'/'で行ける気がします

【ちょこっと解説】
date_separatorのための記述を抜き出すと以下の感じ。

sample.html.haml
 != sprintf(f.date_select(・・・略・・・,date_separator:'%s'),'年','月')+'日'

date_separatorを指定した段階では↓の感じになってると考えてます。

  yyyy %s mm %s dd 

そこにrubyのsprintf関数を使って記述してあげると、以下の指定をしたみたいになります。

   sprintf { yyyy %s mm %s dd } , hash { '年' , '月' }

これで%sの部分に後続で指定したStringを%sに埋め込んであげる。という意味になり結果的に「 yyyy 年 mm 月 dd 」となります。
ただ、これだけだと”日"が入らないため、以下のように指定してあげます。

   sprintf { yyyy %s mm %s dd } , hash { '年' , '月' } + '日'

さらに、hamlの記述が'='のままではString変換されたhtmlがそのまま表示されて酷いことになるので、以下のように'!='指定(明示的にエスケープ処理させる・・・??)をしてあげます。

sample.html.haml
  != sprintf { yyyy %s mm %s dd } , hash { '年' , '月' } + '日'

  # ↓ 実際の記述 ↓

  != sprintf(f.date_select('・・・略・・・',date_separator:'%s'),'年','月')+'日'

これで何とかなった!!!

with_css_classの補足

with_css_classで指定したクラスはあまり意味をなしません笑
実際にCSSを記載するときは、以下のクラス名で指定すればCSSが適用されます。

sample.scss
    .year,.month,.day{
     // 指定したいCSSを記述する
    }

確かにブラウザからhtml確認したら、このクラス名が付与されてます。
↓Chromeの検証[Element]で表示させたらこんな感じ。
Image from Gyazo

Controllerへのデータ受け渡し

date_selectタグで入力した値をController側で受け取るときにも一癖あります。
実際のパラメータの中身を見るとよくわかるのですが、該当項目はhashが更にネストしちゃってます。

{"user"=>{"birthday"=>{"birthday(1i)"=>"2019", "birthday(2i)"=>"8", "birthday(3i)"=>"29"}}}

嫌な予感しかしないですが、この状態で色々試した結果は以下の通り。

sample.rb
 # OKパターン → 普通にDate型としてDB登録可能
 def create
   @user = User.new(params[:user][:birthday])
   @user.save
 end

 # NGパターン → ストロングパラメータで拾ってこれなくて必須の場合エラー
 def create
   @user = User.new(user_params)
   @user.save
 end

private
 def user_params
   params.require(:user).permit(:birthday)
 end

個別指定で行けば保存可能なんですが、他の項目がたくさんある場合は一々そんなの指定してられねえ!!!
と思って、苦肉の策で私はこのように記述しました。

sample.rb
 def create
   params[:user][:birthday] = birthday_join
   @user = User.new(user_params)
 end

private 
  def user_params
    params.require(:user).permit(:birthday)
  end

  def birthday_join
    # パラメータ取得
    date = params[:user][:birthday]

    # ブランク時のエラー回避のため、ブランクだったら何もしない
    if date["birthday(1i)"].empty? && date["birthday(2i)"].empty? && date["birthday(3i)"].empty?
      return
    end

    # 年月日別々できたものを結合して新しいDate型変数を作って返す
    Date.new date["birthday(1i)"].to_i,date["birthday(2i)"].to_i,date["birthday(3i)"].to_i

  end

もしかしたら、ストロングパラメータの記述を頑張れば行けるかもですが、それは試してません。
ポイントは「birthday_join」というメソッドです。
ストロングパラメータ取得前に力技でparamsの中身を日付型にしちゃう作戦です。

適切な処理の仕方をご存知の方は、是非ご教示いただきたいです。。。

まとめ

date_selectタグは超使える子!!
最後まで根気よく仲良くしてあげましょう・・・!!

参考サイト:

「Rails の date_select でつくるセレクトボックスを「年」「月」「日」で区切る」
 → erbでの記載例です。こちらを元にしました。
「date_selectのオプション指定の仕方」
 → ここでは紹介していないオプションも紹介されています。
「Ruby の sprintf で名前付きパラメータ」
 → sprintfについては、ここで学びました

ozackiee
「モノが作れる」エンジニアを目指して学習中です。 学習の軌跡として、まとめやバグなどでハマったことなどを書いて行こうと思います。 <勉強中の言語・フレームワーク・ツール>  ・Ruby,Ruby on Rails  ・HTML/CSS
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした