🍩

【Ruby on Rails】【通知機能】マイページ上でバッジが付与された時に通知する

2024/08/04に公開

はじめに

現在Ruby on Railsを使用し、技術記事投稿アプリを作成しております。
そのアプリ内で通知機能を作成しており、これまで「①自分の記事にいいねがついたとき / ②自分の記事にコメントが投稿されたとき / ③自分がコメントした内容にいいねが押された時」を実装しました。

①②に関しては、こちらの記事を参考に、③は上記記事を参考に自力で実装しました。(実装方法はこちらに投稿しております)

今回は4つ目の通知機能として、マイページ上でバッジが付与された時に通知されるよう実装しました。
(マイページの作成はこちらの記事、バッジ機能作成の記事はこちらご覧ください)

参考になりましたら幸いです。

環境

Rails 7.1.3.4

前提

  • 投稿機能実装済み(この記事ではArticleモデル)
  • 「自分の投稿した記事にいいねが付いた時の通知」「自分の投稿した記事にコメントが投稿された時の通知」「自分がコメントした内容にいいねが押された時」の通知は実装済み
  • 上記3つ実装済のため、通知モデルの作成、通知モデルの関連付は設定済み

実装方法

ここからは、マイページ上でバッジが付与された時に通知する実装内容のみ記載させていただきます。

通知モデルの作成、モデルの関連付け

上記にも記載している通り、すでにNotificationモデル作成、Articleテーブルの関連づけは完了しているため割愛させていただきます。(詳細はこちらと、コメントへのいいねの通知記事ご確認ください)

通知作成メソッドを作る

  • マイページ上でバッジが付与された際の通知に必要なid
    アプリ内では、「1,3,5,10,20,30記事」投稿された際に、ユーザーへバッジが付与されるような実装としております。(この実装内容はこちら)
visitor_id visited_id article_id action checked
現在のユーザーid 現在のユーザーのid 該当の記事のid badge false

これまでの通知機能の実装と異なる点

  • visitor_id、visited_idが共に現在のユーザーidであること。
  • 「1,3,5,10,20,30記事」投稿された際に通知される、という制約をつけていること。

ここまでがマイページ上でバッジが付与された際の通知に必要なidとなります。
この情報を元に通知作成メソッドを実装して行きます。今回マイページ上でバッジが付与された際の通知という内容ですが、読み換えると1,3,5,10,20,30記事が投稿された際に通知するという内容になるため、articleテーブルにメソッドを作成していきます。

その理由は下記の通り、今回バッジデーブルを作成していないためです。
articleテーブルに通知作成メソッドを作った方がわかりやすいと感じたため、下記のような実装をしております。

resources :users, only: %i[new create] do
  collection do
      get :my_articles
      get :my_favorites
      get :my_badges
    end
  end

resources :articles do
  resources :favorites, only: %i[create destroy]
  resources :comments, shallow: true do
    resources :commentfavorites, only: %i[create destroy]
  end
end
  • app/models/article.rb
def create_notification_badge(current_user, article_id)
    count = Article.published.where(user_id: current_user.id).count

    if [1, 3, 5,10,20,30].include?(count)
      save_notification_badge(current_user, article_id)
    end
  end

  def save_notification_badge(current_user, _article_id)
    notification = current_user.active_notifications.new(
      article_id: id,
      visitor_id: current_user.id,
      visited_id: current_user.id,
      action: 'badge'
    )

    notification.save if notification.valid?
  end
end
  • count = Article.published.where(user_id: current_user.id).count: 現在のユーザーが投稿した公開済みの記事の数をカウントしています。公開状態はpublishedスコープを通じて取得しています。
  • if [1, 3, 5,10,20,30].include?(count): この条件式は、記事数が特定の値(1, 3, 5, 10, 20, 30)に一致する場合にtrueを返します。これにより、これらの特定の数値に達したときのみ通知が作成されます。ここで適切に条件指定ができていないと、他の記事数の時にも通知が出てしまいます。
  • save_notification_badgeメソッド: このメソッドでは、ユーザーに対する通知を作成しています。通知の詳細にはarticle_id、通知の送信者(visitor_id)、通知の受信者(visited_id)、そしてアクションタイプ(action)が含まれています。(ここではvisitor_id、visited_id共にcurrent_user.idになる)
  • notification.save if notification.valid?: この行は、通知が有効である場合にのみ保存を試みます。この一文がない場合、通知が有効であっても保存されず、データベースに通知が記録されませんでした。

通知作成メソッドの呼び出し

1,3,5,10,20,30記事が投稿されたタイミングで、通知レコードが作成されます。
先ほど追加したメソッドを、articlesコントローラーのcreateアクションへ追加します。

app/controllers/articles_controller.rb
バッジ付与時の通知、と補足している箇所が通知作成メソッドの呼び出し箇所になります。

def create
    @article = current_user.articles.build(article_params)

    @article.status = if params[:draft].present?
                        :draft
                      else
                        :published
                      end

    if @article.save
      if @article.draft?
        redirect_to article_path(@article), notice: '記事を下書きに入れました。'
      else
        redirect_to article_path(@article), notice: '投稿しました。'
      # バッジ付与時の通知
        @article.create_notification_badge(current_user, @article.id)
      # ここまで
      end
    else
      flash[:error] = 'タイトルと本文を入力しないと、投稿できません'
      render :new, status: :unprocessable_entity
    end
  end

通知一覧画面の作成

1,3,5,10,20,30記事が投稿された通知のviewは下記となります。

app/views/notifications/_notification.html.erb

  <% case notification.action %>
    <% when 'badge' then %>
    <%= link_to 'マイページ', my_badges_users_path, style: 'font-weight: bold;' %>上でバッジが付与されました。
    <%= time_ago_in_words(notification.created_at).upcase %>
  <% end %>

遷移先はマイページ上のバッジ先になります。

これまでの通知機能の実装と異なる点

  • app/views/notifications/index.html.erbで、<% notifications = @notifications.where(visitor_id: current_user.id) %>の一文があります。
    こちらの記事では、where.notとすることで、visitor_idがcurrent_user.idの場合に通知が出ないよう実装しておりますが、今回の内容ではvisitor_id=current_user.idなのでnotを割愛しております。
    (他の通知ではnot付けておいた方がいいのかもしれませんが、一旦このように実装しております)
<h3 class="text-center">通知</h3>
<% notifications = @notifications.where(visitor_id: current_user.id) %>
<% if notifications.exists? %>
<%= render notifications %>
<%= paginate notifications %>
<% else %>
<p>通知はありません</p>
<% end %>

通知作成メソッドが正常に呼び出された時のサーバーログ

記事が作成された後、Notification Createで処理が正常に行われていることがわかります。
また今回必要なidは["visitor_id", 1], ["visited_id", 1], ["article_id", 113], ["action", "badge"], ["checked", false]のため、["comment_id", nil]とcomment_idはnillになっていることもわかります。

Image from Gyazo

通知作成メソッドが失敗している場合

1,3,5,10,20,30記事以外が投稿されたとき、またはそもそもデータベースに通知が記録されていない場合には記事が作成された後、Notification Createで処理が行われないためこのようなログになります。
Image from Gyazo

最後に

個人記事を参考にこれまで4つの通知機能を作成しました。
記事を参考にして実装するだけでなく、自分でロジックを組み立て実装することで流れがより深く理解できました。
最後までお読みいただき、ありがとうございました。

Discussion