🎃
[Rails]通知機能②(helper,case~when,ポリモーフィック関連,MVCの役割)
前回の復習
今回通知させるもの
- ログイン中ユーザーが、他ユーザーからいいねされた時
- フォローしてるユーザーが新規に投稿した時
前回書いた記事・参考資料
前回書いた記事・参考資料
ER図作成時参考
メンターさんに教えていただいたこと
- ポリモーフィック関連を使わず通知機能を作成することもできる
- それぞれ中間テーブルを作成するやり方もある
- このやり方は中間テーブルをいちいち作成するため、面倒というデメリットがある
- 今回作成したポリモーフィック関連では、どの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.id
やfavoite.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 対象オブジェクト
when 値1 then
# 値1と一致するときの処理
when 値2 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" だったら ➜ 本のページにリダイレクト
- それ以外なら ➜ 関連ユーザーのページにリダイレクト
参考文献
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
の部分。
参考文献
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
通知機能
Discussion