未経験からエンジニアへの転職を目指しています。
初投稿ですのでわかりにくい箇所があるかもしれませんがご容赦ください。
本題です。
Railsでいいねのランキング機能を実装中に、週間いいねランキングも作りたいと思い実装しました。
※いいねランキングの実装は以下の記事を参考にしました
https://qiita.com/mitsumitsu1128/items/18fa5e49a27e727f00b4
今回は週間いいねランキング(前週の月曜〜前週の日曜)を表示する方法を書いていきます。
モデル名等は適宜ご自身のものに置き換えてください。
前提
- 料理(cooks):いいね(likes)=1:N
- いいね機能の実装は完了している
モデルにメソッドを定義
def self.last_week # メソッド名は何でも良いです
Cook.joins(:likes).where(likes: { created_at: 0.days.ago.prev_week..0.days.ago.prev_week(:sunday)}).group(:id).order("count(*) desc")
end
順番に解説していきます。
※joinsメソッドについてわからない方は以下の記事が参考になります
https://pikawaka.com/rails/joins
Cook.joins(:likes)
でcooksテーブルとlikesテーブルを内部結合しています。
内部結合したテーブルから
where(likes: { created_at:0.days.ago.prev_week..0.days.ago.prev_week(:sunday)})
で先週の月曜日(0.days.ago.prev_week)から先週の日曜日(0.days.ago.prev_week(:sunday))の間にいいねをされた料理を全て取り出しています。
取り出した料理に対し、
group(:id)
でidが被っている料理をグループ化し、
order("count(*) desc")
でいいねの数をカウントして、いいね数が多い順に並べています。
(countの引数に*を使用していますがあまり理解できていません・・・)
もし、取り出す料理数に制限をかけたい場合は、
limit(5)
を末尾につけるといいねの数が多い順で5個取り出すことが出来ます。(1位〜5位を表示する)
コントローラーにモデルで定義したメソッドを記載
def weekly_rank
@ranks = Cook.last_week
end
コントローラの可読性を高めるためにモデルにメソッドを定義しましたが、コントローラーを以下のようにしても同様です。
def weekly_rank
@ranks = Cook.joins(:likes).where(likes: { created_at: 0.days.ago.prev_week..0.days.ago.prev_week(:sunday)}).group(:id).order("count(*) desc")
end
ビューを記載
<div class="rank-container">
<% @ranks.each.with_index(1) do |cook, i| %>
<div class="rank-box">
<%= i %>位
<div class="card shadow-lg">
<%= link_to cook_path(cook) do %>
<%= attachment_image_tag cook, :image, :fill, 200, 120, class:"card-img-top"; %>
<% end %>
<%= link_to user_path(cook.user) do %>
<span class="account ml-2 mt-2">By <%= cook.user.account %></span>
<% end %>
<div class="card-body pt-1 pb-1">
<p class="card-title mb-0">◆<%= cook.name.truncate(10) %></p>
<p class="mb-1"><%= cook.comment.truncate(13) %></p>
<div class="row border-top m-auto">
<div class="col-6">
<%= link_to user_path(cook.user) do %>
<%= attachment_image_tag cook.user, :account_image, :fill, 50, 50, fallback: "no_image.jpg", class:" rounded-circle no-image"; %><br>
<% end %>
</div>
<div class="col-5 offset-1 pt-3">
<%= link_to "詳細", cook_path(cook), class: "btn btn-sm btn-dark" %>
</div>
</div>
</div>
</div>
</div>
<% end %>
</div>
最後に
最後まで読んで頂きありがとうございます!
今回は週間ランキングでしたが、whereの引数の期間を変えれば、月間ランキング等も作れると思います!
上記内容は一例ですのでもっとスマートな方法があれば教えてほしいです!
また、誤りがあればご指摘ください!