はじめに
Rails でカレンダーを簡単に取り扱えそうな simple_calendar という gem の存在を知りました。
そこで、週表示のカレンダーで、それぞれの日に予定を入れるフォームを作るとどんな感じになるか、サンプルを作りながら検証しました。
view は読みやすくするために haml も導入して試そうと思います。
環境の前提
- Rails 5.1.6
- ruby 2.4.3
目標
下記のような、日毎に入力フォームがある週表示カレンダーの作成を目指します。
手順
1. 初期設定
rails アプリケーション新規作成
以下コマンドを実行します。
$ rails new calendar-sample
$ cd calendar-sample
Gem インストール
今回利用する simple_calendar, haml-rails をインストールします。
# 追記
gem 'simple_calendar', '~> 2.0'
gem 'haml-rails'
$ bundle
simple_calendar の view テンプレートを生成
あとから simple_calendar のデザインを修正できるように、テンプレートを生成します。
$ rails g simple_calendar:views
haml に変換
haml-rails のコマンドで haml に変換します。
$ rake haml:erb2haml
サンプル Model作成
表示確認用の Meeting モデルを scaffold で作成します。
$ rails g scaffold Meeting name start_time:date content:string
simple_calendar のカレンダー表示設定
週表示でカレンダーを表示できるよう、simple_calendar を設定します。
-# 追記
= week_calendar do |date|
= date
表示確認
Migrateしてサーバを起動します。
$ rails db:migrate
$ rails s
http://localhost:3000/meetings にアクセスし、週表示カレンダーが表示されていることを確認します。
2. カレンダーのフォーム作成
route 登録
一括でデータ登録用のメソッドを routes に定義に定義します。
Rails.application.routes.draw do
resources :meetings do
collection do
post :update_week
end
end
end
view 実装
日毎に content が入力できるようなフォームを実装します。
-# 以下に書き換え
%h1 Week Meetings
= form_for :meeting, url: update_week_meetings_path, html: { method: :post } do
= week_calendar do |date|
= date
- meeting = @meetings.find_or_initialize_by(start_time: date)
- if meeting.id.nil?
%p
= hidden_field_tag "meeting[#{date}][start_time]", date
%p
= text_field_tag "meeting[#{date}][content]"
- else
= fields_for "meeting[]", meeting do |meeting_fields|
%p
= meeting_fields.hidden_field :start_time
%p
= meeting_fields.text_field :content
= submit_tag
メソッドに find_or_initialize_by
を使うことで、レコードの新規作成・編集どちらにも対応できるようにしています。
また、 meeting.id
の有無で処理を分岐させていますが、これはクエリパラメータの形を統一するためです。
既存データはidをキーとしたハッシュで格納されるのに対し、新規データはidがないのでハッシュの配列で格納されます。
idがある場合
"meeting"=>
{"1"=>{"start_time"=>"2018-07-02", "content"=>"A"},
"2"=>{"start_time"=>"2018-07-03", "content"=>"B"}}
idがない場合
"meeting"=>
[{"start_time"=>"2018-07-02", "content"=>""},
{"start_time"=>"2018-07-03", "content"=>""}]
そのため、配列が入ったクエリパラメータをPOSTしようとすると下記エラーが生じるため、ハッシュを使う形に統一できるようにしています。
Rack::QueryParser::ParameterTypeError (expected Hash (got Array) for param `meeting'):
参考URL
controller 設定
view で入力された複数日のデータを一括で登録・更新するためのメソッドを実装します。
# 追記
def update_week
week_meetings_params.keys.each do |key|
@meeting = Meeting.find_or_initialize_by(start_time: week_meetings_params[key][:start_time].to_date)
@meeting.update_attributes(week_meetings_params[key])
end
redirect_to meetings_path
end
# 中略...
private
# 追記
def week_meetings_params
params.require(:meeting).permit!
end
http://localhost:3000/meetings にアクセスし、週ごとのフォームが更新できることを確認します。
終わりに
突貫で作成したサンプルなので粗い部分もあるかと思いますが、simple_calendar を使った週表示のフォームを試すことが出来ました。カレンダー部分の処理をシンプルに取り扱えて便利だなと思いました。