Zenn
🎃

[Rails]通知機能②(helper,case~when,ポリモーフィック関連,MVCの役割)

2025/03/23に公開

前回の復習

今回通知させるもの

  • ログイン中ユーザーが、他ユーザーからいいねされた時
  • フォローしてるユーザーが新規に投稿した時



前回書いた記事・参考資料
メンターさんに教えていただいたこと
  • ポリモーフィック関連を使わず通知機能を作成することもできる
    • それぞれ中間テーブルを作成するやり方もある
    • このやり方は中間テーブルをいちいち作成するため、面倒というデメリットがある
    • 今回作成したポリモーフィック関連では、どのuser.idなのか取ってくる情報が遠くなりわかりづらいというデメリットがある

モデル

ポリモーフィック関連の書き方

belongs_to :○○, polymorphic: true

polymorphic: trueが「ポリモーフィック関連」を表している。
polymorphic: trueを書くことで、「○○_type」と「○○_id」が自動で作成される。
これはRailsでのルール。

notification.rb(今回実際に書いたポリモーフィック関連)

belongs_to :user
belongs_to :notifiable, polymorphic: true
  • belongs_to :notifiable で、「notifiable」という名前のポリモーフィック関連を作成しますよ
  • polymorphic: true で以下2つが作成される
    • notifiable_type には、投稿なのかいいねなのか、元のモデル名が入る。
    • notifiable_id には、通知の対象となる元のID(book.idfavoite.id)の数字が入る

favorite.rb

has_one :notification, as: :notifiable, dependent: :destroy

after_create do
    create_notification(user_id: book.user_id)
end

notification(通知)モデルとの関連性を上記で書いている。

  • 1個のいいねに対して、通知は1個(has_one)
  • 通知は「notifiable」としますよ、「notifiable」と呼びますよ(as~)
  • いいねが作成された後に、通知を作成します(after_create)
  • notificationのuser_idは、bookのuser_idにしてください

book.rb

has_many :notifications, as: :notifiable, dependent: :destroy

一人のユーザーに対して、たくさんの通知がある。(has_many)

user.rb

has_many :notifications, dependent: :destroy

as: :notifiable はつけない。
as: :notifiable をつけると、「UserはNotificationから見てnotifiableとして参照される側だ」と宣言することになってしまう。⇒notifiable_type: 'User'があることになってしまう❌


コントローラーの作成

通知状態を更新するコントローラーを作成。

  • 未読の通知を既読に変更する(updateアクション)
rails g controller Notifications

notifications_controller.rb

class NotificationsController < ApplicationController
  before_action :authenticate_user!

  def update
    # params[:id] によって、ログイン中のユーザーの通知IDを取得。(他人の通知は見られないようにしてる)
    notification = current_user.notifications.find(params[:id])
    # 取得した通知を「既読」にアップデート。
    notification.update(read: true)
    # 通知が何のオブジェクトに関するものか(Bookなのか、それ以外なのか)を見て、リダイレクト先を変更
    case notification.notifiable_type
    when "Book"
      redirect_to book_path(notification.notifiable)
    else
      redirect_to user_path(notification.notifiable.user)
    end
  end
end

case~when とは

基本の形

case  対象オブジェクト
when1 then
  # 値1と一致するときの処理
when2 then
  # 値2と一致するときの処理
else
  # どれにも当てはまらないときの処理
end

then は省略してOK。

今回のコード

case notification.notifiable_type
when "Book"
  redirect_to book_path(notification.notifiable)
when "Favorite"
  redirect_to user_path(notification.notifiable.user)
end

今回は、notification.notifiable_type という値(文字列)を見て、

  • もし "Book" だったら ➜ 本のページにリダイレクト
  • それ以外なら ➜ 関連ユーザーのページにリダイレクト

参考文献

https://www.javadrive.jp/ruby/if/index9.html#google_vignette
https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html#case
https://www.sejuku.net/blog/19467


helperの作成

helperとは?

ビューにロジックを持たせないために使用する。
「通知の種類によって、通知メッセージを変更する」というロジックは、helperに持たせる。

def notification_message(notification)
     case notification.notifiable_type
     when "Book"
       "フォローしている#{notification.notifiable.user.name}さんが#{notification.notifiable.title}を投稿しました。"
     else
       "投稿した#{notification.notifiable.book.title}#{notification.notifiable.user.name}さんにいいねされました。"
     end
   end
 end
復習・MVCの役割

notification.rbに書いてもOK

ロジックなので、モデルファイル(notification.rb)に書いてもOK。

  • _helperのデメリットは、継承元が高い・クラス階層が高いので、どこからでも呼び出せる
    • つまり、メソッド名がかぶらないようにしないと必要ないところで呼び出されてしまう
    • メソッド名をかぶらないように命名するのが大変

こういった場合はモデルに書くと楽!
モデルに書くと、レシーバーが不要になる。

レシーバーとは

レシーバ-

puts book.name

上記例だと、bookの部分がレシーバー。
ただのnameだと何のnameから、どのファイルからデータを持ってきたらいいかわからない。
bookのnameですよと明示的にしてあげるのをレシーバーと呼ぶ。

case notification.notifiable_type

上記だと、notificationの部分。


参考文献

https://qiita.com/you8/items/e5f5c27cfed60a23fa75

 def message
    case self.notifiable_type
    when "Book"
      "フォローしている#{self.notifiable.user.name}さんが#{self.notifiable.title}を投稿しました。"
    when "Favorite"
      "投稿した#{self.notifiable.book.title}#{self.notifiable.user.name}さんにいいねされました。"
    when "Relationship"
      "#{self.notifiable.follower.name}さんにフォローされました。"
    end
  end

参考文献

helper

https://railsguides.jp/action_view_helpers.html
https://qiita.com/yukiyoshimura/items/f0763e187008aca46fb4

通知機能

https://zenn.dev/redheadchloe/articles/8f8a82855d19dc
https://zenn.dev/goldsaya/articles/0f387f3e62ff92
https://qiita.com/nekojoker/items/80448944ec9aaae48d0a
https://qiita.com/ki_87/items/6feb324140bf5b0349ff
https://qiita.com/bty__/items/2db1dd4fcd7945b980f7
https://qiita.com/tktk0430/items/bdb8fbcf4ce3258b2d41

Discussion

ログインするとコメントできます