🦡

DM機能つけたけど、DM気づかないよね通知機能

2024/07/18に公開

DM機能がつけられても、いちいちフォロー/フォロワーのマイページへ行って、DMを送るをしないとDMが来てるかどうかわからない。現実的じゃないから、通知機能をつけたい。けど、さっぱりわからないので、まとめ

モデル作成

rails g model Notification user:references message:references read:boolean default:false
rails db:migrate
  • さっきの記事でも書いた、referencesは既にあるテーブルを参照。
  • read:boolean default:falseは、
    notifications(通知って意味)テーブルに新しい通知が作成された時に、
    その通知が未読であることを示すために使う。

read:boolean default:falseの使用目的

  • 新しい通知が作成されると、自動的にreadカラムfalseに設定
  • ユーザーが通知を確認した時に、readカラムtrueに更新することで、
    どの通知が既読であるかを追跡できる。

モデルファイルの編集

app/models/notification.rb
class Notification < ApplicationRecord
  belongs_to :user
  belongs_to :message

  validates :user_id, presence: true
  validates :message_id, presence: true
  validates :read, inclusion: { in: [true, false] }
end
  • presence: trueは空文字を許可しない
  • validates :read, inclusion: { in: [true, false] }
    `inclusionを使うことで、readカラムに格納される値が、true,falseのどちらかになる。

通知コントローラー

app/controllers/public/messages_controller.rb
class Public::MessagesController < ApplicationController
  before_action :authenticate_user!

  def create
    @message = current_user.messages.build(message_params)
    if @message.save
      create_notification(@message)
      redirect_to room_path(@message.room)
    else
      redirect_back(fallback_location: root_path)
    end
  end

  private

  def message_params
    params.require(:message).permit(:room_id, :message)
  end

  def create_notification(message)
    room = message.room
    recipient_entry = room.entries.where.not(user_id: message.user_id).first
    recipient = recipient_entry.user
    Notification.create(user: recipient, message: message)
  end
end
  • 解説
 def create
    @message = current_user.messages.build(message_params)
    if @message.save
      create_notification(@message)
      redirect_to room_path(@message.room)

@message = current_user.messages.build(message_params)現在のユーザーに紐づいた新しいメッセージを作成する。

「 buildメソッド 」の使い方

  • 関連するモデルの新しいインスタンスを作成するために使用する
  • 特定の関連付けを持つ親モデルで使用されるため、新しいインスタンスが自動的に親モデルに関連づけられる

まとめ

buildメソッドはそのコレクションに新しいメッセージを追加するけど、
保存はできないため、データベースに保存するには、saveメソッドが必要。
そして、createメソッド記述して、新しいインスタンスを作成し、即座にデータベースに保存させる。
buildメソッド

saveメソッド

createメソッド

else
  redirect_back(fallback_location: root_path)
end
  • メッセージの保存が失敗した時の処理で、
    保存されなかったら、元のページへリダイレクト。元のページがわからない場合は、ホームページへリダイレクトする。
params.require(:message).permit(:room_id, :message)
  • room_idmessageを許可。
def create_notification(message)
    room = message.room
    recipient_entry = room.entries.where.not(user_id: message.user_id).first
    recipient = recipient_entry.user
    Notification.create(user: recipient, message: message)
  end
end
  • room = message.roomメッセージが属するチャットルーム取得
  • recipient_entry = room.entries.where.not(user_id: message.user_id).first[recipientが受信者って意味]
    メッセージを送信したユーザー以外のユーザーエントリーを取得する
  • recipient = recipient_entry.user上記で取得したエントリーから、通知を受け取るユーザーを取得する。
  • Notification.create(user: recipient, message: message)受信者(recipient)とメッセージを指定して、新しい通知を作成する(create)

まとめ

create_notificationメソッドを使って、新しいメッセージが送信された時に自動的に通知が生成される。

通知の表示

app/controllers/public/notifications_controller.rb
class Public::NotificationsController < ApplicationController
  def index
    @notifications = current_user.notifications.where(read: false)
  end 
  
  def mark_as_read
    notification = current_user.notifications.find(params[:id])
    notification.update(read: true)
    redirect_to notifications_path
  end 
end

  • 解説
def index
  @notifications = current_user.notifications.where(read: false)
end
  • 現在ログインしてるユーザー(current_user)の未読通知(read: false)を取得するよう記述
  • 取得した未読通知は、インスタンス変数`@notificationsに格納され、ビューで通知を表示できるようになる
def mark_as_read
  notification = current_user.notifications.find(params[:id])
  notification.update(read: true)
  redirect_to notifications_path
end
  • mark_as_readアクションは、特定の通知を既読にするため
  • params[:id]を使って、現在ログインしてるユーザーの特定の通知を見つける。この通知のIDはパラメーターとして渡される。
  • notification.update(read: true)「read: false」から「true」にupdateする。これにより、通知が既読としてマークされる。

ルーティング

config/routes.rb
  scope module: 'public' do
    resources :notifications, only: [:index] do
      member do
        patch 'mark_as_read'
  • memberは個別の追加ルートを定義。ここでは、特定の通知に対するpatchリクエストを定義している。
  • patch 'mark_as_read通知を既読にするためのルートを定義している
     [ PATCH /notifications/:id/mark_as_read ]
  • indexアクション = "全ての未読通知を一覧表示"するためのルート
    (get/notifications)
  • mark_as_readアクション = "特定の通知を既読"にするためのルート

ビュー作成

app/views/layouts/application.html.erb
<header>
  <%= link_to notifications_path, class: "btn btn-sm btn-light" do %>
    <i class="fa-solid fa-bell" style="color: #af7546;"></i> 通知
      <% if current_user.notifications.where(read: false).any? %>
        <span class="badge badge-danger"><%= current_user.notifications.where(read: false).count %></span>
    <% end %>
   <% end %>
  </header>

application.html.erbに追記した(ヘッダーに)

  • <% if current_user.notifications.where(read: false).any? %>
    条件文で、未読の通知があるかどうかをチェックする
  • where(read: false)は、read属性がfalse(未読)の通知。
    any?で未読通知が1つでもあるかどうかを確認します。
    未読通知があれば、trueなければfalseを返す。
  • <%= current_user.notifications.where(read: false).count %>は、未読通知の数を表示する

以上 !

Discussion