背景
- Railsで個人アプリケーションを作成していましたが、今月の予定表を作る必要がありました。そこで、コントローラー側でRubyを用いてプログラムを書けば、ビューで表示できるかと思ってので実装してみました。変数との関連性と計算に時間が掛かりましたが、そこまで難しいレベルではありませんので参考になればと思い、記事を書かせていただきました。外国人なので変な日本語が混じってるかもしれませんが、ご指摘いただければ幸いです。
目次
- Dateクラスについて
- timesメソッドについて
- コントローラーの実装
- ビューの実装
- 参考サイト
Dateクラスについて
DateクラスはRubyの組み込みクラスであり、今回使用したのは以下のメソッドです。
- Date.today
今日の日付を取得します。今年の場合、戻り値は2021-01-28で年月日の形式になります。
now = Date.today
- Date.today.year
今年の値を取得します。戻り値は2021になります。
this_year = Date.today.year
- Date.today.month
今月の値を取得します。戻り値は1になります。
this_year = Date.today.month
- Date.today.wday
今日の日付を取得します。戻り値は0から6までの値です。
戻り値 | 意味 |
---|---|
0 | 日曜日 |
1 | 月曜日 |
2 | 火曜日 |
3 | 水曜日 |
4 | 木曜日 |
5 | 金曜日 |
6 | 土曜日 |
weekday = Date.today.wday
- Date.today.beginning_of_month
今月の初日を取得します。戻り値は2021-01-01になります。
first_day = Date.today.beginning_of_month
timesメソッドについて
- timesは同じ処理を回数分だけ繰り返す時に使うメソッドです。
- 使い方
回数.times do |変数|
10.times do |i|
(処理)
end
コントローラーの実装
以上のメソッドを踏まえて、コントローラーの実装を行いました。全体のコードは以下の通りです。
class SdatesController < ApplicationController
def index
date_today
end
private
def date_today
@now = Date.today
@wday_jan = ["月","火","水","木","金","土","日"]
@this_year = @now.year
@this_month = @now.month
@first_day = @now.beginning_of_month
@last_day = (@first_day + (7-@first_day.wday))
@week_period = (@first_day..@last_day)
@last_day2 = (@last_day + (7-@last_day.wday))
@week_period2 = ((@last_day+1)..@last_day2)
@last_day3 = (@last_day2 + (7-@last_day2.wday))
@week_period3 = ((@last_day2+1)..@last_day3)
@last_day4 = (@last_day3 + (7-@last_day3.wday))
@week_period4 = ((@last_day3+1)..@last_day4)
@last_day5 = (@last_day4 + (7-@last_day4.wday))
@week_period5 = ((@last_day4+1)..@last_day5)
@last_day6 = (@last_day5 + (7-@last_day5.wday))
@week_period6 = ((@last_day5+1)..@last_day6)
end
end
今回のカレンダー機能と関係あるところはprivate以下のコードです。
長いように見えますが、@last_day2以下は同じような処理の繰り返しです。
- まずは今日の日付を変数@nowに代入します。
@now = Date.today
- wdayメソッドは戻り値が数字であるため、曜日として表示するための配列@wday_janを用意します。
@wday_jan = ["月","火","水","木","金","土","日"]
例えば、@wday_jan[1]だった場合、"月"が出力されるようにします。
- 今年の値を@this_yearに代入します。
@this_year = @now.year
- 今月の値を@this_monthに代入します。
@this_month = @now.month
- 今月の初日を取得するために.beginning_of_monthメソッドを使います。値は@first_dayに代入します。
@this_month = @now.month
- 初日から最初の週(first weekend)の末日(日曜日)を計算し、
値を@last_dayに代入します。@last_dayは「初日の日付 + 日曜日までの日数」であり、
ここでポイントになるのはが「日曜日までの日数」の計算です。
@wday_janには["月","火","水","木","金","土","日"]が格納されて"1"が"月"、"2"が"火"・・・"0”が"日"などのようにマッチングしています。例えば、初日が水曜日だった場合、@wday_janには"水"="3"です。水曜日から最初の週の末日(日曜日)までの日数は"7-3"となります。この関係を数式で表現すると「@wday_janの配列の数-初日の曜日数(3)」になります。代入した変数で式を表すと以下になります。
@last_day = (@first_day + (7-@first_day.wday))
- 次は初日から最初の週の末日までの日付らをRangeオブジェクト@week_periodに代入します。
@week_period = (@first_day..@last_day)
- 同じように第2週目、第3週目....の月曜~日曜までのRangeを求めます。繰り返しになるので説明は割愛します。
@last_day2 = (@last_day + (7-@last_day.wday))
@week_period2 = ((@last_day+1)..@last_day2)
...以下、繰り返し部分を省略
- index.html.erbテンプレートで表示させるために、privateで定義した関数date_todayを記述します。
(上記、コードは省略)
def index
date_today
end
ビューの実装
コントローラーで定義したメソッドをindex.html.erbテンプレートに表示するための記述をします。
<div class="schedule_title">
<h1>Schedule Board</h1>
</div>
<div id="todays_date">
<%= @this_year %>年<%= @this_month %>月
</div>
<table border="1" id="sdate_table">
<thead>
<tr>
<th class="sdate_name">月</th>
<th class="sdate_name">火</th>
<th class="sdate_name">水</th>
<th class="sdate_name">木</th>
<th class="sdate_name">金</th>
<th class="sdate_name">土</th>
<th class="sdate_name">日</th>
</tr>
</thead>
<tbody>
<tr>
<% 7.times do |x| %>
<td>
<% @week_period.each do |period| %>
<% if x == (period -1).wday %>
<%= period %>
<% end %>
<% end %>
</td>
<% end %>
</tr>
<tr>
<% 7.times do |x| %>
<td>
<% @week_period2.each do |period| %>
<% if x == (period -1).wday %>
<%= period %>
<% end %>
<% end %>
</td>
<% end %>
</tr>
<tr>
<% 7.times do |x| %>
<td>
<% @week_period3.each do |period| %>
<% if x == (period -1).wday %>
<%= period %>
<% end %>
<% end %>
</td>
<% end %>
</tr>
<tr>
<% 7.times do |x| %>
<td>
<% @week_period4.each do |period| %>
<% if x == (period -1).wday %>
<%= period %>
<% end %>
<% end %>
</td>
<% end %>
</tr>
<tr>
<% 7.times do |x| %>
<td>
<% @week_period5.each do |period| %>
<% if x == (period -1).wday %>
<%= period %>
<% end %>
<% end %>
</td>
<% end %>
</tr>
<% if Random.rand(@week_period6).month == @this_month %>
<% 7.times do |x| %>
<td>
<% @week_period6.each do |period| %>
<% if x == (period -1).wday %>
<%= period %>
<% end %>
<% end %>
</td>
<% end %>
</tr>
<% end %>
</tbody>
</table>
- timesメソッドを使い、テーブルの1行ごとに日付を表示させます。の間を7回繰り返すことによって1週間の日付を出力します。
<% 7.times do |x| %>
<td>
<% @week_period.each do |period| %>
<% if x == (period -1).wday %>
<%= period %>
<% end %>
<% end %>
</td>
<% end %>
-
if文を使い、繰り返しの変数xと@week_periodに格納されている日付らを変数periodに代入。日付から1を引いた後に、その日付の曜日(0~6の値)とxが一致した場合にのみ表示するようにします。つまり、変数xには1週間分を繰り返す機能と同時に月曜日〜日曜日まで(1,2,3,〜0)までindexの機能を持たせます。こうすることによってこのindexと一致した日付の値のみが表示されます。
-
最後の週には次月の日付が入ってしまったりする場合があるため、if文を使って分岐させます。
<% if Random.rand(@week_period6).month == @this_month %>
Random.rand(変数)メソッドを使い、変数内の中からランダムで一つの値を取得します。
@week_period6には最後の週の日付らが入ってます。その日付らのどれかになります。(1月25日〜31日までのどれか)その値に.monthメソッドを使い、月を取得します(1月)。それと@this_month(実際の今月。例えば、今日が2月2日の場合は2月)が一致した場合にのみ、表示するようにします。
参考サイト
https://www.javadrive.jp/ruby/for/index6.html
https://qiita.com/geshi/items/685a0814d77688fb1a55
https://qiita.com/youcune/items/f5371d449d2486c67357