実装したい内容
gemのsimple calendarを使ってカレンダーに予約の予定を入れていく
rubyやRailsの基礎知識があること前提で話を進めていきます
開発環境
Rails 6.0.3
ruby 2.7.0
reservationsテーブルの追加
今回はミニアプリを作る想定をしreservationsテーブルを作成しname(string)とstart_time(datetime型)のカラムを追加していきます。
rails new calendar_app
まずはお決まりのrails new
bundle
bundle installも癖づけて行いましょう。
gem 'simple_calendar', '~> 2.0'
bundle
gemfileにsimple_calendarを追加したら再びbundle install
rails g scaffold reservationc name start_time:datetime
今回はスキャフォルドを使って簡単にアプリを実装していきたいと思います。
rails db:migrate
お決まりのrails db:migrateも忘れないように。
rails sで http://localhost:3000/ にアクセス!
しっかり立ち上がっていることが確認できたら
root 'reservations#index'
続いてsimple_calendarのviewを整えていきます
rails g simple_calendar:views
create app/views/simple_calendar
create app/views/simple_calendar/_calendar.html.erb
create app/views/simple_calendar/_month_calendar.html.erb
create app/views/simple_calendar/_week_calendar.html.erb
ファイルが3つ作成されたのですが今回はmouthを使用していきたいと思います。
*= require simple_calendar
# simple_calendarのcssを読み込む
<p id="notice"><%= notice %></p>
<h1>Reservations</h1>
<table>
<thead>
<tr>
<th>Name</th>
<th>Start time</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @reservations.each do |reservation| %>
<tr>
<td><%= reservation.name %></td>
<td><%= reservation.start_time %></td>
<td><%= link_to 'Show', reservation %></td>
<td><%= link_to 'Edit', edit_reservation_path(reservation) %></td>
<td><%= link_to 'Destroy', reservation, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<!-- ここから --!>
<%= month_calendar events: @reservations do |date, reservations| %>
<%= date %>
<% reservations.each do |reservation| %>
<div>
<%= reservation.start_time.hour %>:<%= reservation.start_time.min %>
<%= reservation.name %>
</div>
<% end %>
<% end %>
<!-- ここまで追加 --!>
<%= link_to 'New Reservation', new_reservation_path %>
予約を追加するとしっかりとカレンダーにも反映されます♪
これだけではつまらないのでバリデーションを追加していきましょう。
特殊なバリデーションを自作する
今回は予約の数を制限したいので土日は予約不可。
過去の日付は選択できない
予約できる時間帯は13:15と19:15のみと言った物凄い特殊なバリデーションを組んでいきたいと思います!
class Reservation < ApplicationRecord
validates :name, presence: true
validate :date_before_start
validate :start_time_not_sunday
validate :start_time_not_saturday
validate :time_only
validates :start_time, uniqueness: { message: 'は他のユーザーが予約しています' }
def date_before_start
errors.add(:start_time, "は過去の日付を選択できません") if start_time < Date.today
end
def start_time_not_sunday
errors.add(:start_time, "は日曜日を選択できません") if start_time.sunday?
end
def start_time_not_saturday
errors.add(:start_time, "は土曜日を選択できません") if start_time.saturday?
end
def time_only
if hour_only_1 && min_only
true
elsif hour_only_2 && min_only
true
else
errors.add(:start_time, "(時間)は13:15もしくは19:15になります")
end
end
def hour_only_19
start_time.hour == 19
end
def hour_only_13
start_time.hour == 13
end
def min_only
start_time.min == 15
end
end
date_before_timeは過去の日付を選択できないことを表しています。
start_time_not_subdayとstart_time_notsaturdayで土日を予約不可とします!
start_time.sunday?などでdate_time(型は)日曜?ですか?みたいな感じに表すことができます!
ここからが本番!!
13:15分と19:15分の2つの時間に予約を限定していきます.
start_time.hourで時間を指定でき、start_time.minで分数を指定できるので
これを13時、19時、15分と限定していきます!
time_onlyメソッドを作成し時間を限定します!!
またstart_time をuniqqueness: trueにすることにより、同じ時間でも予約が不可になるので1日に取れる最大の予約数は2件となります!!
番外編
今回はかなり特殊な形だったのでバリデーションを自作していきましたが、datetimeのバリデーションには
validates_timelinessといった便利なgem があります!
https://github.com/adzap/validates_timeliness
# in Gemfile
gem 'validates_timeliness', '~> 5.0.0.beta1'
# Run bundler
$ bundle install
例えば予約時間を9時から5時までの間に限定したい場合は
validates_time :booked_at, between: ['9:00am', '5:00pm']
みたいな形に書くと簡単に実装できます!!
※このgemはrails5に対応したgemなのでrails6だとコンフリクトする可能性があります