前回投稿した通知機能をポリモーフィックを使って実装しましたが、途中からうまく使えていませんでした。
下記記事のenumの設定から分岐してviewまでを修正して書いていきます。
この記事から見られた場合はenumまでは下記記事を見てください
enumの設定
enum action_type: {
favorited_the_diary: 0,
followed_you: 1,
commented_on_the_diary: 2
}
通知する内容をなんとなく翻訳にかけて分かるように書いてあります
後で日本語化するので単語一個だと分かりにくくなります
create時に通知を入れる
通知したい内容がcreateされたときにactivityをcreateするようにします
after_create_commit :create_activities
private
def create_activities
Activity.create!(subject: self, user_id: ユーザーのID, action_type: Activity.action_types[:enumで設定した内容])
end
各モデルにafter_create_commitを入れます
これはDB保存が完了した時をトリガーに動きます
詳しくはRailsガイドをみてください
今回入れたい通知は保存したタイミングで大丈夫ですが内容によって好きなタイミングでcreate_activityが動くように書いてください
create_activitiesの説明
-
subject: self
これでDB保存ができた内容がはいります(typeとid) -
user_id: ユーザーのID
DB保存した内容からuser_idを取り出して書いてください
例:いいねのとき
user_id: diary.user.id(いいねに紐づいてる投稿に紐づいてるユーザーのID) -
action_type: Acticity.action_types[:enumで設定した内容]
右で書いた文はenumで設定した内容から値を出力しています
例:いいねのとき
action_type: Activity.action_types[:favorited_the_diary]これでaction_typeに0が入ります
ターミナルで確認してみます
いいねが保存された後にcreate_activitiesが動いて保存されたのが確認できます
ここで正確に保存が出来ているか確認してください
※user_idがいいねとアクティビティで同じ値なのは自分の投稿をいいねしたためです
コントローラーとルーティングの設定
ここからは好きなように書いて問題ありません
未読だけ表示、同じ投稿へのいいねはまとめる、どのタイミングで見たことにするのか、いろいろカスタマイズしてください
ここではすべての通知の一覧表示と一覧表示から各通知を押したときに既読にする設定で実装しています
viewファイルのすべては書きません、レイアウトは頑張ってください
rails g でコントローラーを作って設定していきます
class Public::ActivitiesController < ApplicationController
before_action :authenticate_user
def index
@activities = current_user.activities.order(created_at: :desc).page(params[:page]).per(20)
end
def read
activity = current_user.activities.find(params[:id])
unless activity.read?
activity.update(read: true)
end
redirect_to activity.subject.redirect_path
end
コントローラーの説明
-
before_action :authenticate_user
deviseのメソッドでユーザー以外をはじきます -
index
表示したい内容をkaminariを使って20件ずつ作成日時の新しい順でいれます -
read
通知一覧から各通知をクリックした際にすべてここを通して処理します
通知を読んだらtrueにして各通知元へリダイレクトさせます -
redirect_to activity.subject.redirect_path
ここでsubjectにモデルの情報が入っているので、モデルにあるインスタンスメソッドを呼び出します
ポリモーフィック設定でcaseやifを使わずに分岐させることが出来ます
モデルにredirect_pathを書いていきます
def redirect_path
#コメントの場合
"/#{diary.user.name_id}/diaries/#{diary.id}"
end
Rrefixで書けないためURLで書きます
#{}でかこうことで変数展開ができます
好きなリダイレクト先を入れてください。
resources :activities, only: [:index] do
patch :read, on: :member
end
resurcesに読んだ時の処理をするルートをネストで入れてます
viewの作成
最低限の表示だけ書いています
<% if @activities.present? %>
<% @activities.each do |activity| %>
<%= link_to read_user_activity_path(current_user.name_id,activity), method: :patch do %>
<%= @activity.subject.name %>さんが<%= @activity.action_type_i18n %>
<% end %>
<%= paginate @activities %>
<% end %>
<% else %>
<p>通知はありません</p>
<% end %>
ここでもポリモーフィックの利点である同じコードでモデルごとに違う内容を表示します。
subject.nameと書きましたがnameカラムがないモデルもあります
モデルにインスタンスメソッドを書きます
def name
#favorite.rbの場合
user.name
end
enumの日本語化
activityのaction_typeを日本語化して表示させます
詳しくはrails日本語化で検索するとたくさん出てきます
下記方法でできなかったら調べてみてください
application.rbに日本語化の文を書きます
module NaganoCake
class Application < Rails::Application
:
config.i18n.default_locale = :ja
:
end
end
ja.ymlファイルを作って下記を書きます
ja:
enums:
activity:
action_type:
favorited_the_diary: "投稿にいいねしました"
followed_you: 'あなたをフォローしました'
commented_on_the_diary: '投稿にコメントしました'
以上で日本語になります
rails cでコンソールを開いて確認することが出来ます
action_typeに_i18nをつけると日本語で表示されます
実装は以上です
表示できましたでしょうか
まとめ
今回は通知機能をポリモーフィックを使って実装していきました
メソッドをそろえることでコードを変えずに表示を変えることが出来ます。
通知機能をいれるために覚えておくこと
- 通知用でモデルが必要
- 任意のタイミングで通知モデルをcreate
ポリモーフィックで覚えておくこと
- モデル情報ごと保存することが出来る
最後に
通知機能をポリモーフィックで作りましたが、ポリモーフィックで得られるメリットを最大限にすることを目的でコードをつくりました。redirect_pathは正直controllerにまとめて書いておいてもいいかなと思います。
polimorphic_pathという書き方もあるのですが私はrouteを変にカスタマイズしたせいで使えませんでした。確実にできる方法で書いてあります。興味のある方は調べてみてください。
ポリモーフィック自体はしっかり使えると便利だと思うので使いどころを考えていきたいですね。
いろんな書き方ができるため、どの方法が一番いいのかの判断をできるようにしたいです。