LoginSignup
21
26

More than 3 years have passed since last update.

【Rails】日付・期間を指定した投稿をトップページに自動的に表示する

Last updated at Posted at 2019-01-21

個人開発の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型にしておきます。

入力フォーム

new.html.erb
期間の開始日
<%= date_field_tag 'post[start_on]', nil %>
期間の終了日
<%= date_field_tag 'post[end_on]', nil %>

date_field_tagを使うと下の写真のようにカレンダー形式で日付を指定できるので便利です。

{11AAE812-54BD-4360-9D52-624F342E84C3}.png

controller

バリデーション

開始と終了の日付が正しく指定されたかどうかチェックするバリデーションはmodelではなくcontrollerで行っています。

posts_controller.rb
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から検索

posts_controller.rb
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_onend_onとの日付を比較しながらDBから探してくれるんですね。とても便利です。

トップページ

index.html.erb
<%= render partial: 'special_posts', collection: @special_posts, as: :post %>

トップページのviewであるindex.html.erbには上記のコードを書きました。指定期間がマッチする投稿データ@special_postsを、部分テンプレートspecial_postsに表示するようにしています。

ちなみに@special_postsに格納されたデータをすべて繰り返しレンダリングするうえでcollectionを使っています。each doよりもN+1問題に対応できるそうです。

_special_posts.html.erb
タイトル
  <%= post.title %>
本文
  <%= post.body %>
期間開始日
  <%= post.start_on %>
期間終了日
  <%= post.end_on %>

あとがき

以上が大筋の流れとなります。こう書いてしまうと簡単に思えますけど、じぶんにとっては難しかったです。まだまだ未熟ですね。これからも必要に応じて学んでいきます。

21
26
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
26