個人開発のWebアプリ**「まちかどルート」**をもうすぐv5.0正式版にバージョンアップします。
そのv5.0正式版にむけて現在v5.0rc1でテスト中なのが、投稿にあらかじめ日付・期間を指定しておき、その日付・期間が来たらトップページに自動的に表示される機能です。
プログラミングに入門して7ヶ月弱。初めての挑戦だったのでメモとして残します。
データベース
まず、期間の開始日start_on
と終了日end_on
というカラムをPosts
テーブルに作成します。
$ rails g migration AddStartToPosts start_on:date
$ rails g migration AddEndToPosts end_on:date
$ rails db:migrate
いずれのカラムもdate型にしておきます。
入力フォーム
期間の開始日
<%= date_field_tag 'post[start_on]', nil %>
期間の終了日
<%= date_field_tag 'post[end_on]', nil %>
date_field_tag
を使うと下の写真のようにカレンダー形式で日付を指定できるので便利です。
controller
バリデーション
開始と終了の日付が正しく指定されたかどうかチェックするバリデーションはmodelではなくcontrollerで行っています。
def create
(中略)
sabun = (@post.start_on - Date.today).to_i
unless sabun >= 1
flash[:error] = "開始日は明日以降で!"
render 'new'
return
end
sabun = (@post.end_on - @post.start_on).to_i
unless sabun <= 10
flash[:error] = "期間は最長10日間まで!"
render 'new'
return
end
unless sabun >= 0
flash[:error] = "終了日は開始日以降で!"
render 'new'
return
end
(中略)
end
開始日は明日以降とするため、上記のようにして今日Date.today
との日付の差分sabun
を1日以上にするようバリデーションしています。
ほかにも、指定期間を最長10日間とするため差分を10日以下としたり、終了日は開始日以降とするために差分を0以上となっています。
指定期間にマッチする投稿をDBから検索
def index
(中略)
special_post_ids = Post.where.not(start_on: nil).pluck(:id)
@special_posts = Post.where(id: special_post_ids).where('start_on <= ?', Date.today).where('end_on >= ?', Date.today)
(中略)
end
トップページのviewであるindexに投稿のデータをわたすため、controllerで上記の処理を行います。
まず、すべての投稿の中から期間が指定されている投稿のみidを抽出してspecial_post_ids
に格納します。
続いて、そのidをもとに開始日start_on
と終了日end_on
の期間内にマッチする投稿データを検索して@special_posts
に格納する、という流れです。
とくにwhere('start_on <= ?', Date.today)
という検索方法を使ったことがなかったので苦労しました。Date.today
という書式を使うとそこに今日の日付が自動的に代入されてstart_on
やend_on
との日付を比較しながらDBから探してくれるんですね。とても便利です。
トップページ
<%= render partial: 'special_posts', collection: @special_posts, as: :post %>
トップページのviewであるindex.html.erb
には上記のコードを書きました。指定期間がマッチする投稿データ@special_posts
を、部分テンプレートspecial_posts
に表示するようにしています。
ちなみに@special_posts
に格納されたデータをすべて繰り返しレンダリングするうえでcollection
を使っています。each do
よりもN+1問題に対応できるそうです。
タイトル
<%= post.title %>
本文
<%= post.body %>
期間開始日
<%= post.start_on %>
期間終了日
<%= post.end_on %>
あとがき
以上が大筋の流れとなります。こう書いてしまうと簡単に思えますけど、じぶんにとっては難しかったです。まだまだ未熟ですね。これからも必要に応じて学んでいきます。