[Rails]月間、週間、日別でランキング機能を実装(Time.current)

先日、基本的なランキング機能の表示方法を記事にしたので、今回はランキング機能の応用編ということで、月間、週間などの期間を指定してのランキング機能を実装していきます。

先日書いた記事はこちら
[[Rails]いろんなランキング表示(いいね、コメント、投稿数)](https://qiita.com/nakachan1994/items/ace3508d5192c58efdf1)

同率順位表示する記事もあげました
[ランキング機能の順位を同率表示する](https://qiita.com/nakachan1994/items/9ecf25fe1835415d9ae2)

#開発環境

> ruby 2.6.3
> Rails 5.2.6

#前提

- 投稿サイトを想定
- ランキングの順位に応じて１位、２位などの順位を表示
- ranksコントローラーのrankアクションに処理を記述
- rank.html.erbでビューを表示

モデル名、変数名等は適宜、ご自身の開発環境に変換してお考えください。

user  ユーザー
post  投稿
like  いいね
comment  コメント

#ビュー

postとuserで渡す変数や表示させたいカラムが違うだけなので、先にやっつけておきます。
postのランキングを例にします。

`１位、２位と順位を表示したいので、with_indexを使います。`

```erb:views/ranks/rank.html.erb
<!--配列の1つ目から順に1位、２位と表示される-->
<% post_ranks.each.with_index(1) do |post, i| %>
  第<%= i %>位
:
<!--表示したいカラムをご自由に-->
:
<% end %>
```

こうするだけで、順位が表示されるようになります。

#これだけ押さえておけばいい

実際のランキング表示方法の前に、これだけ押さえておけばいいポイントを説明します。
ずばり、`Time.current`です!
`Time.current`さえ理解できたら期間指定系のランキング機能は９割実装できたも同然です！

Time.currentとはRails独自のメソッドです。
Time.currentを使うことで、今の日時が取得できます。

ではコンソールで試してみましょう！

```
#　rails cを実行
$rails c

# Time.currentを実行すると現在の日時が表示される
001 > Time.current
=> Wed, 07 Jul 2021 01:25:38 UTC +00:00 
```

これでTime.currentで現在の日時が取得できることがわかったはず。
とても便利なメソッドです。

このTime.currentを軸に今月、今週、今日とデータを取得していきます。
方法は簡単で`Time.current.all_week`とすると現在の日時を含む全ての週、つまり今週という期間を指定できます。

ではコンソールで試していきます。

```
# 今月を表示
002 > Time.current.all_month
# すると今が2021年7月なので2021/7/1~2021/7/31までが指定される
=> Thu, 01 Jul 2021 00:00:00 UTC +00:00..Sat, 31 Jul 2021 23:59:59 UTC +00:00 

# 今週を表示
003 > Time.current.all_week
=> Mon, 05 Jul 2021 00:00:00 UTC +00:00..Sun, 11 Jul 2021 23:59:59 UTC +00:00 

# 今日を表示
004 > Time.current.all_day
=> Wed, 07 Jul 2021 00:00:00 UTC +00:00..Wed, 07 Jul 2021 23:59:59 UTC +00:00 
```

しっかりと対象の期間が取得できています。
たとえば、Time.current.all_weekではなく、`'指定の日時'.all_week`で指定の日時を含む週を取得できたり、`Time.current.ago(2.years)`で今日の2年前を取得できたりもするので、色々覚えておくと便利だと思います。

[時刻や日付を扱うメソッドの基本情報まとめ【Ruby】【Rails】](https://fuchiaz.com/ruby-rails-time-date/)

では以上を踏まえて実際にコードを書いていきます。


#月間ランキング

月間ランキングでは、ユーザーの投稿数のランキングを例にしていきます。

```controllers/ranks_controller.rb
def rank
  # 月間ランキング
  @month_user_post_ranks = User.where(id: Post.group(:user_id).where(created_at: Time.current.all_month).order('count(user_id) desc').pluck(:user_id))
end
```

解説します。

```controllers/ranks_controller.rb
#Postモデルのuser_idが同じのまとめる
Post.group(:user_id)
#投稿が作られた日が今月のデータのみ抽出
where(created_at: Time.current.all_month)
#user_idが多い順に並べる
order('count(user_id) desc')
#user_idで取り出す
pluck(:user_id)
#Userモデルのidが一致するデータを取得する
User.where(id: )
```

これで、今月のユーザーの投稿数ランキングができました。

#週間ランキング

週間ランキングでは、投稿のいいね数ランキングを例にしていきます。

```controllers/ranks_controller.rb
def rank
  # 週間ランキング
  @week_post_like_ranks = Post.find(Like.group(:post_id).where(created_at: Time.current.all_week).order('count(post_id) desc').pluck(:post_id))
end
```

解説します。

```controllers/ranks_controller.rb
# Postモデルから()内のデータを探してくる
Post.find()
# 次にLikeモデルのpost_idが同じものをまとめる
Like.group(:post_id)
#投稿が作られた日が今週のデータのみ抽出
where(created_at: Time.current.all_week)
# まとめたものをpost_idの多い順に並び替える
order('count(post_id) desc')
# そのままだとLikeモデルで取り出してしまうので、post_idで値を取りだす
pluck(:post_id)
```

これで今週の投稿のいいね数ランキングができました。

#日別ランキング

日別ランキングでは、投稿のコメント数ランキングを例にしていきます。

```controllers/ranks_controller.rb
def rank
  # 日別ランキング
  @today_post_comment_ranks = Post.find(Comment.group(:post_id).where(created_at: Time.current.all_day).order('count(post_id) desc').pluck(:post_id))
end
```

いいね数ランキングと考え方は同じで、いいねをコメントに、all_weekをall_dayに変更しただけなので、詳しい説明は割愛させていただきます。

#最後に

今回はTime.currentメソッドを使って期間を指定してランキング機能を実装しました。
時間を扱えるメソッドはTime.current以外にもたくさんあって、メソッドの使い分けをしていくようです。
ぼくもまだまだ知らないメソッドだらけなので、日々勉強していきます。

最後まで見て頂きありがとうございました。