4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Rails]ページの閲覧数をカウントする方法

Last updated at Posted at 2022-12-04

考え方

ER図はこちら
作成するモデルはReadCountのみです
ER図.png

各Bookのshowページにアクセスした時に以下の処理を行う
・本のidと訪れたユーザーのidをReadCountに登録する

閲覧数を表示するには
・該当するBookを探す Book.find(params[:id])等
・アソシエーションを用いて該当するbook_idを持つReadCountのデータを数える
例:book_idが1の場合
book.find(1).read_counts.count

前提条件
ruby 3.1.2
Rails 6.1.7
device、bootstrap導入済み(bootstrapは見た目の問題なので機能には関係なし)
User及びBookモデル作成済み

1.モデルの作成

integer型か、既存のテーブルを参照するreferences型のどちらかで記述
integer型の場合

ターミナルの書き方.rb
rails g model ReadCount user_id:integer book_id:integer

references書く場合はこちら
若干書き方が違う( 〜_idが不要になる)ので注意

ターミナル書き方.rb
rails g model ReadCount user:references book:references

migrationファイルを確認して問題なければ、migrateも忘れずに

rails db:migrate

2.アソシエーションの設定

1人のユーザーは複数の閲覧データを持つので
user : read_count = 1 : N
1つの本は複数の閲覧データを持つので
book : read_count = 1 : N
よって下のように設定します

user.rb
  has_many :read_counts, dependent: :destroy
book.rb
  has_many :read_counts, dependent: :destroy
read_count.rb
  #references型なら入力済みの筈
  belongs_to :user
  belongs_to :book

3.contorollerへの記述

今回はBookの閲覧数なので、新しくcontorollerは作成しません

books_controller.rb
class BooksController < ApplicationController
 def show
    @book = Book.find(params[:id])#bookを該当するidで取得
    read_count = ReadCount.new(book_id: @book.id, user_id: current_user.id)
    #ReadCountを新しく作成し、book_idに取得してきた本のid、user_idにcurrent_user = つまり自分のidを入力
    read_count.save
    #上2行を纏めて書くとこちら
    current_user.read_counts.create(book_id: @book.id)#createはsave不要
 end
end

※応用

このままだとアクセスするたびにReadCountが作成されてしまいます
例えば一度閲覧したユーザーを数えたくない場合

ReadCount.find_by(user_id: current_user.id, book_id: @book.id)
・ReadCountの中に、取得したbook_idとユーザーのidが一致するものが無いかを探し

unless
・合致するものがなかった場合(falseの場合)にcurrent_user.read〜を実行する
という処理で実装出来ます。纏めると以下の通りです。

books_controller.rb
class BooksController < ApplicationController
 def show
    @book = Book.find(params[:id])
    unless ReadCount.find_by(user_id: current_user.id, book_id: @book.id)
      current_user.read_counts.create(book_id: @book.id)
    end
 end
end

また閲覧数のカウントを1つの投稿に付き1人の1日1回まで数えるならば
Time.zone.now.all_day
・今日のデータを取得
where(created_at: Time.zone.now.all_day)
・今日created_at:された、つまり今日作成されたReadCountのデータを抽出
.find_by(user_id: current_user.id, book_id: @book.id)
・Book.findで取得したbook_idとユーザーのidが一致するものが無いかを探す。あとは上と一緒
という処理を組み合わせ実装出来ます。纏めると以下の通りです。

books_controller.rb
class BooksController < ApplicationController
 def show
    @book = Book.find(params[:id])
    unless ReadCount.where(created_at: Time.zone.now.all_day).find_by(user_id: current_user.id, book_id: @book.id)
      current_user.read_counts.create(book_id: @book.id)
    end
 end
end

4.viewページへの記述

考え方にも記載しましたが、book.read_counts.countで閲覧数を求めることが出来ます
後は必要な箇所に追記してください

_index.html.rb
<tbody>
    <% books.each do |book| %>
      <tr>
        <td><%= link_to(book.user) do %>
          <%= image_tag book.user.get_profile_image, size:'50x50' %>
          <% end %>
        </td>
        <td><%= link_to book.title,book %></td>
        <td><%= book.body %></td>
        <td id="js-book_favorite_<%= book.id %>">
          <%= render "favorites/nice", book: book %>
        </td>
        <td>コメント数:<%= book.book_comments.count %></td>
        <td>閲覧数:<%= book.read_counts.count %></td> #ここに追加
      </tr>
    <% end %>
  </tbody>
show.html.rb
<table class='table'>
  <tr>
    <td><%= link_to(@book.user) do %>
      <%= image_tag @book.user.get_profile_image, size:"100x100" %><br>
      <%= @book.user.name %>
      <% end %>
    </td>
    <td><%= link_to @book.title, @book %></td>
    <td><%= @book.body %></td>
    <td id="js-book_favorite_<%= @book.id %>">
      <%= render 'favorites/nice', book: @book %>
    </td>
    <td>コメント数:<%= @book.book_comments.count %></td>
    <td>閲覧数:<%= @book.read_counts.count %></td> #ここに追加
    <% if @book.user.id == current_user.id %>
      <td><%= link_to 'Edit', edit_book_path(@book), class: "btn btn-sm btn-success" %></td>
      <td><%= link_to 'Destroy', book_path, method: :delete, data: { confirm: '本当に消しますか?' }, class: "btn btn-sm btn-danger"%></td>
    <% end %>
  </tr>
</table>

最後に

ご覧いただいた方、ありがとうございました
意見、感想等ありましたらご自由にご記入ください

4
3
0

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
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?