👝

通知機能の実装 Part2 (通知を受け取れるようにする)

2023/10/07に公開

この記事で分かること

  • 通知機能の基礎
  • いいね、フォロー、コメント、DMの通知を受け取る

前提条件

  • ポリモーフィック関連付けが完成している
  • いいねなどの通知を送りたい機能が実装済みである

「ポリモーフィック関連付け」は前記事で紹介しました。
https://zenn.dev/tya0116/articles/4195f169c38d6b

また今回の実装は以下の記事を参考にし実装しました。
https://qiita.com/sazumy/items/479cb14cfea77c7429bd

前回の「ポリモーフィック関連付け」では、いいね、コメント、フォローの部分を関連付けていましたが、プラスでDMも通知を受け取れるように再設定しています。

それでは、よろしくお願いします。

完成イメージ

complate_demo

ER図

er_figure_focus

全体のER図

er_figure_all

実装手順

  1. 各モデルにアクションを追加する
  2. コントローラに記述
  3. viewの記述
  4. helper.rbでリンクの場合わけ

実装方法

実装手順に沿って紹介します。

各モデルにアクションを追加する

notification.rb
  belongs_to :subject, polymorphic: true
  belongs_to :user

  enum action_type: { commented_to_own_post: 0, favorited_to_own_post: 1, followed_me: 2, chated_to_own_post: 3}

【Point(notification)】

  • ポリモーフィックの関連付けを(blongs_to)で示す
  • (action_type)で何の(いいねやコメントなどの)通知なのかを数値で場合わけ
favorite.rb
  has_one :notification, as: :subject, dependent: :destroy
  after_create_commit :create_notifications

  private

  def create_notifications
    Notification.create!(subject: self, user: item.user, action_type: :favorited_to_own_post)
  end
post_comment.rb
  has_one :notification, as: :subject, dependent: :destroy
  after_create_commit :create_notifications

  private

  def create_notifications
    Notification.create!(subject: self, user: item.user, action_type: :commented_to_own_post)
  end
relationships.rb
    has_one :notification, as: :subject, dependent: :destroy
    after_create_commit :create_notifications

    private
    
    def create_notifications
      Notification.create!(subject: self, user: follower, action_type: :followed_me)
    end
chats.rb
  has_one :notification, as: :subject, dependent: :destroy
  after_create_commit :create_notifications

private

  def create_notifications # 1. チャットが属する部屋を取得
    room = self.room # 2. チャットが属する部屋の中で、自分以外のユーザーを取得
    other_users = room.users.where.not(id: self.user.id) # 3. 最初の相手ユーザーを取得
    recipient_user = other_users.first # 4. 相手ユーザーに通知を作成
    Notification.create!(subject: self, user: recipient_user, action_type: :chated_to_own_post)
  end
end

【Point】

  • (after_create_commit)は、ここでは「そのモデルの機能が保存されたらこのアクションを行ってね」という意味
  • (create_notifications)は、「subject:自身のモデル,user: どのユーザに通知を届ける?,行うアクションは?」という順で記載
  • relationshipsの「user: どのユーザに通知を届ける?」では「ログインユーザーがフォローしているユーザーのソース名」を記述
  • chatsでは、先に相手ユーザーの情報を取得するようにコードを記述(DMの実装方法によって異なる)
  • privateで記述すること(同じメソッド名を使うため)

Routeingの設定

routes.rb
 resources :notifications, only: [:index]

Controllerの記述

notifications_controller
  def index
    @notifications = current_user.notifications.order(created_at: :desc)
  end

Viewを作成

続いてViewの作成をしていきます。

基盤となるviewを作成

notifications/index.html.erb
<div class= "container py-5 px-sm-0">
  <div class= "row">
    <div class="col-10 offset-1">
    <% if @notifications.present? %>
      <h4>通知一覧<span class= "text-warning"><i class="fa-sharp fa-solid fa-bell"></i></span></h4>
      <% @notifications.each do |notification| %>
      <table class='table table_group'>
      <%= render notification.action_type, notification: notification %>
      </table>
      <% end %>
    <% else %>
      <div class="text-center">
      通知はありません
    <% end %>
    </div>
  </div>
</div>
<%= render notification.action_type, notification: notification %>とは

renderで(notification.action_type)ファイルを呼び出すことができます。
これにより、タイプ名と同じファイルを作成することで、「いいね通知ではこの記述で」のように文章を記述できます。

タイプ別でviewを作成

現在のnotificationタイプは以下の4つです。

  • commented_to_own_post・・・コメント通知
  • favorited_to_own_post・・・いいね通知
  • followed_me・・・フォロー通知
  • chated_to_own_post・・・DM通知

これら上記の文章を作っていきます。

タイプ名と同じファイル名でviewを作成

notifications/commented_to_own_post.html.erb
<td>
  <%= image_tag notification.subject.user.get_profile_image(30,30),class: "img_icon" %>
  <%= link_to notification.subject.user.name, user_path(notification.subject.user) %>
 さんがあなたの
  <%= link_to '投稿', item_path(notification.subject.item) %>
  にコメントしました!(<%= notification.subject.created_at.strftime('%Y/%m/%d') %>)
</td>
notifications/favorited_to_own_post.html.erb
<td>
    <%= image_tag notification.subject.user.get_profile_image(30,30),class: "img_icon" %>
    <%= link_to notification.subject.user.name, user_path(notification.subject.user) %>
    さんがあなたの
    <%= link_to '投稿', item_path(notification.subject.item) %>
    にいいねしました!(<%= notification.subject.created_at.strftime('%Y/%m/%d') %>)
</td>

notifications/followed_me.html.erb
<td>
    <%= image_tag notification.subject.following.get_profile_image(30,30),class: "img_icon" %>
    <%= link_to notification.subject.following.name, user_path(notification.subject.following) %>
    さんがあなたをフォローしました!(<%= notification.subject.created_at.strftime('%Y/%m/%d') %>)
</td>
notifications/chated_to_own_post.html.erb
<td>
  <%= link_to checked_notification_path(notification), method: :PATCH do %>
      <%= image_tag notification.subject.user.get_profile_image(30,30),class: "img_icon" %>
      <%= link_to notification.subject.user.name, chat_path(notification.subject.user) %>
     さんからメッセージが届いています!(<%= notification.subject.created_at.strftime('%Y/%m/%d') %>)
  <% end %>
</td>

ヘッダーにリンクを追加したら完成です。

_header.html.erb
<%= link_to notifications_path do %>
 <span class= "text-warning"><i class="fa-sharp fa-solid fa-bell"></i></span>
<% end %>

complate

既読機能の追加

https://zenn.dev/tya0116/articles/86b189e502b115

感想

DMなら相手ユーザーに通知を届けたいのに自身のみに通知が届くなど、上手くいかないことが多かったです。ヘルパーやrenderの使い方など新しいことが知れたので時間はかかったが実装できてよかったです。このまま既読機能と削除機能の作成に移ります。

この記事をかいた人

https://twitter.com/tya_dwc
23/6/1にDWCに入学し、主にRailsの学習に取り組みました。卒業が近づきこれから何で学習をするか悩んだときに、技術ブログをしようと考えました。初心者ですがよろしくお願いします。

Discussion