LoginSignup
12
13

More than 3 years have passed since last update.

Railsで通知機能を作る(①基本機能編)

Last updated at Posted at 2021-02-26

やったこと

Railsでアプリを作る課題を行っています。通知機能を作りましょうというタスクがありました。
初めて作る&覚えておくと応用が効きそうなので、いかにやり方をまとめます。

なお、実行環境は以下の通りです。

  • Rails 5.2.3
  • Ruby 2.6.4

仕様

以下のような仕様になっています。

  • userがフォローされた時
  • userの投稿したpostにコメントがついた時
  • userの投稿に「いいね!」がされた時

上記の条件でユーザーに通知を出します。

DB設計

こちらのようになっています。

Image from Gyazo

ポリモーフィック関連付けをしようして、activity.subjectの形で、Like, Comment, Relationshipのインスタンスが呼び出せるようにしています。
データベース構造の詳細はこちらの記事をご覧ください。

Railsのポリモーフィック関連付けを理解する

また、activitiesテーブルのreadカラムも利用して、既読管理も行いますが、これは、本記事ではなく、次回の記事にて紹介します。

ゴール

上記のテーブル設計からactivitiesのレコードを作成し、現在のuserのものだけを集約し、それを一覧表示する」ことが今回のゴールとなりそうです。

通知機能

Model

今回は、

  • userがフォローされた時 => relationshipsのレコードが作られた時
  • userの投稿したpostにコメントがついた時 => commentsのレコードが作られた時
  • userの投稿に「いいね!」がされた時 => likesのレコードが作られたとき

上記3つのアクションが行われたときに、activitiesのレコードも同時に作られれば良さそうです。

それは、以下の方法で実装しました。モデルメソッドに書いた内容を、3つまとめて紹介します。

class Like < ApplicationRecord
  # 中略
  after_create_commit :create_activities

  private

  def create_activities
    Activity.create!(subject: self, user: post.user, action_type: :liked_to_own_post)
  end
end

class Relationship < ApplicationRecord
  # 中略
  after_create_commit :create_activities

  private

  def create_activities
    Activity.create!(subject: self, user: follower, action_type: :followed_me)
  end
end

lass Comment < ApplicationRecord
  # 中略
  after_create_commit :create_activities

  private

  def create_activities
    Activity.create!(subject: self, user: post.user, action_type: :commented_to_own_post)
  end
end

create_activitiesのメソッドを、Like, Relationship, Comment, のインスタンスが作られた後で呼んでいます。使用しているafter_create_commitなのですが、after_saveと似ているコールバックです。ただし、データベース変更のコミットが完了するまでトリガされない点が異なるそうです。

詳しい説明はRailsガイドのこちらの記述をどうぞ。

なお、modelにはそれぞれ、ポリモーフィック関連付けを定義する記述もつけています。こちらは、先に挙げたこちらの記事をご覧ください。

今思うと、各モデルのcreate_activitiesがプライベートメソッドなのは、別々のモデルに同名のメソッドを使っているからなのですね。。。

(当初は、お手本のメソッドの写経をしていましたが、今、改めて見直してみて思うです。。。)

さて、これで基本的な通知機能は実装できました。まだviewができていないので、console上で実験すると...

$ rails c
> user = User.first
> user.activities
#=> Activityのインスタンスたちが取得できる

上記のコマンドでuserに紐づく通知一式が取得できます。これをeachで回せば、viewで表示できそうです。

追記)Viewで通知を表示する

続けて、Viewを続けて実装します。

仕様は以下の通りです。3種類ある通知をクリックすると、それぞれ以下のページに遷移します。

  • 自分がフォローされた時の通知 => フォローしてくれたユーザーの詳細ページ
  • 自分の投稿へのコメントの通知 => 該当の投稿
  • 自分の投稿へのいいねの通知 => 該当の投稿

それぞれの遷移先は、以下のように設定します。(本当はモデルメソッドとして実装しましたが、記事の範囲内で動作させるために、一時的にヘルパーに記載しています。)

some_helper.rb
module SomeHelper

  def transition_path(activity)
    case activity.action_type.to_sym
    when :commented_to_own_post
      post_path(activity.subject.post, anchor: "js-comment-#{activity.subject.id}")
    when :liked_to_own_post
      post_path(activity.subject.post)
    when :followed_me
      user_path(activity.subject.follower)
    end
  end
end

そして、action_type(通知のタイプ)と同じ名前のビューを作り...
(ここではサンプルに1例だけ載せます)

views/mypage/activities/_liked_to_own_post.html.slim
= link_to transition_path(activity) do
  object
   = link_to activity.subject.user.username, user_path(activity.subject.user)
  | があなたの
  object
    =link_to '投稿', post_path(activity.subject.post)
  | にいいねしました
  .text-right
    = l activity.created_at, format: :short

controllerにて、current_userのものだけ集約したactivity

app/controllers/mypage/activities_controller.rb
class Mypage::ActivitiesController < Mypage::BaseController
  def index
    @activities = current_user.activities.order(created_at: :desc)
  end
end

viewでこんな感じに回すのでした。

views/mypage/activities/index.html.slim
- if @activities.present?
  - @activities.each do |activity|
    = render "#{activity.action_type}", activity: activity
- else
  .text-center
    | お知らせはありません

renderで呼び出す内容って、動的に生成できるのですね^^

上記の内容で、以下のようにページが表示できました。

Image from Gyazo

以上、簡単ですが、ユーザーへの通知の設定です。ここから、既読管理を作り込んでいきます。

12
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
13