はじめに
Railsアプリ作成時にgem 'simple_calendar', '~> 2.0'
を使ったので、その際に困った
TimeWithZone
で時間操作する点について記載して行きたいと思います。
バージョン
Rails 6.0.3
Ruby 2.6.6
参考資料
simple_calendar公式ドキュメント
https://github.com/excid3/simple_calendar
TimeWithZone 参考サイトです
https://api.rubyonrails.org/v6.0.2.1/classes/ActiveSupport/TimeWithZone.html
https://www.javadrive.jp/ruby/time_class/index2.html
作業内容
カレンダー作成は割愛させて頂きます!
最初のコードはこんな感じになります。
基本的なcrud処理
class EventsController < ApplicationController
def index
@events = Event.all
end
def new
@event = Event.new
end
def show
@event = event.find(params[:id])
end
def create
Event.create(event_params)
redirect_to events_path
end
def destroy
@event = event.find(params[:id])
@event.destroy
redirect_to events_path, notice:"削除しました"
end
def edit
@event = Event.find(params[:id])
end
def update
@event = Event.find(params[:id])
if @event.update(event_params)
redirect_to events_path, notice: "編集しました"
else
render 'edit'
end
end
private
def event_params
params.require(:event).permit(:title, :content, :start_time)
end
end
<%= form_with(model: @blog, local: true) do |form| %>
<div class="title">
<%= form.label :title %>
<%= form.text_field :title %>
</div>
<div class="time">
<%= form.label :start_time %>
<%= form.datetime_select :start_time %>
</div>
<div class="content">
<%= form.label :content %>
<%= form.text_field :content %>
</div>
<div class="submit">
<%= form.submit %>
</div>
<% end %>
viewに関してはform内がタイトル・開始時刻・内容
と言う感じで
僕がしたい内容とは少し違っていました。
イベントカレンダーを作りたかったので、日付+開始+終了時刻
を設けたいと考えました。
end_time(終了時刻)
start_day(開始日時)も追加しようとしていたのですが、
データとして保持する際にstart_time
に日付の情報が入ってくるので省きます。
その代わりモデルに
attr_accessor :start_day ⇦記載
パラメーターとしてこの形で受け取れる
[2] pry(#<EventsController>)> @event.start_day
=> {1=>2021, 2=>7, 3=>22}
viewファイルも変更
.
.
.
<div class="form-group">↓追加
<%= form.label :start_day, "時刻" %>
<%= form.date_select :start_day, {discard_year: true}, class: "form-control" %><br>
</div>
<div class="form-group">
<%= form.time_select :start_time, class: "form-control" %>
~ ↓追加
<%= form.time_select :end_time, class: "form-control" %>
</div>
.
.
コントローラーでの処理も変更
@event = Event.create(event_params)
このままだと対応できないので、
下記の処理に変更
@event = Event.new(event_params)
@event.start_time = ~~~~
@event.end_time = ~~~~
@event.save
@event.start_time
で開始時刻+作成日
が作れます
同じく@event.end_time
で終了時刻+作成日
が作成される。
作成日
はタイムスタンプとして自動的に入ってしまう。
なので、入力欄に2月9日として投稿したとしても、、
2月3日(作成日)に追加されてしまう。
pry(#<EventsController>)> @event.start_time
=> Wed, 03 Feb 2021 18:44:00 JST +09:00
そこで@event.start_day
から[年][月][日]取得し上書きしてあげる。
pry(#<EventsController>)> @event.start_day
=> {1=>2021, 2=>2, 3=>9}
[年] [月] [日]
なので、シンプルに記述
@event.start_time = @event.start_day
結果
1=>2021, 2=>2, 3=>9, 4=>0, 5=>0
[年] [月] [日] [時] [分]
うん!今のままだと当然[時][分]
が取得出来てない 笑
@event.start_dayからは「年」「月」「日」
が取得。
@event.start_timeからは「時間」「分」
が取得。
これを採用した新しいTimeWithZoneのインスタンスを作成して代入すれば解決します。
なので、
一旦この形にまとめます!
Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
安易な変数に変えておきます。
d = @event.start_day.values ⇦ 値のみを取得したいのでvaluesメソッドを使っています!
s = @event.start_time
e = @event.end_time
pry(#<EventsController>)> Time.zone.local(d[0], d[1], d[2], s.hour, s.min)
=> Tue, 09 Feb 2021 18:44:00 JST +09:00
うまく出来たのであとはこれを代入してあげれば完成!
@event.start_time = Time.zone.local(d[0], d[1], d[2], s.hour, s.min)
@event.end_time = Time.zone.local(d[0], d[1], d[2], e.hour, e.min)
class EventsController < ApplicationController
def index
@events = Event.all
end
def new
@event = Event.new
end
def show
@event = Event.find(params[:id])
end
def create
@event = Event.new(event_params)
d = @event.start_day.values
s = @event.start_time
e = @event.end_time
@event.start_time = Time.zone.local(d[0], d[1], d[2], s.hour, s.min)
@event.end_time = Time.zone.local(d[0], d[1], d[2], e.hour, e.min)
if @event.save
redirect_to events_path, notice: 'リストを作成しました'
else
flash.now[:alert] = "#{@event.errors.messages.length}つ空欄です。"
render :new
end
end
def destroy
@event = Event.find(params[:id])
@event.destroy
redirect_to events_path, notice:"削除しました"
end
def edit
@event = Event.find(params[:id])
end
def update
@event = Event.find(params[:id])
if @event.update(event_params)
redirect_to events_path, notice: "編集しました"
else
render 'edit'
end
end
private
def event_params
params.require(:event).permit(:title, :content, :start_time, :end_time, :start_day)
end
end
おわりに
@event.start_day
から値を取り出すことにかなり苦戦しました^^;
いろんな変換メソッドを試したり、formヘルパーを触ってみたり
なかなか答えに辿りつきませんでした。
中身はハッシュで,欲しいのは「値」。「ハッシュ」から「値」に変換する
だけの話でした。
何をしないといけないかをしっかり考えることが重要だと今回で改めて気付きました。^^