LoginSignup
0
1

More than 3 years have passed since last update.

【Rails】通知機能の実装

Posted at

実装機能

フォローまたはチャットの通知を一覧で受け取る
未読のものがあった場合、ヘッダー部分に未読マークをつける

モデル作成

$ rails g model Notification
00000000000_create_notifications.rb
class CreateNotifications < ActiveRecord::Migration[5.2]
  def change
    create_table :notifications do |t|
      t.integer :visitor_id, null: false
      t.integer :visited_id, null: false
      t.integer :relationship_id
      t.integer :chat_id
      t.string :action, default: '', null: false
      t.boolean :checked, default: false, null: false

      t.timestamps
    end

    add_index :notifications, :visitor_id
    add_index :notifications, :visited_id
    add_index :notifications, :relationship_id
    add_index :notifications, :chat_id
  end
end

・visitor_id (通知を送ったユーザーのid)
・visited_id (通知を送られたユーザーのid)
・relationship_id (フォローid)
・chat_id (チャットid)
・action (通知の種類(フォロー、チャット))
・checked (通知を送られたユーザーが通知を確認したかどうか)

$ rails db:migrate

関連付け アソシエーション

app/models/user.rb
  has_many :active_notifications, class_name: 'Notification', foreign_key: 'visitor_id', dependent: :destroy
  has_many :passive_notifications, class_name: 'Notification', foreign_key: 'visited_id', dependent: :destroy

・active_notifications(自分からの通知)
・passive_notifications(相手からの通知)

app/models/relationship.rb
  has_many :notifications, dependent: :destroy
app/models/chat.rb
  has_many :notifications, dependent: :destroy
app/models/notification.rb
class Notification < ApplicationRecord
  default_scope -> { order(created_at: :desc) }
  belongs_to :relationship, optional: true
  belongs_to :chat, optional: true

  belongs_to :visitor, class_name: 'User', foreign_key: 'visitor_id', optional: true
  belongs_to :visited, class_name: 'User', foreign_key: 'visited_id', optional: true
end

・optional: true (nilを許容)

通知メソッド実装

フォローされた時、チャットが送られてきた時に通知がnotificationテーブルに登録されるように

app/models/chat.rb
 def create_notification_chat!(current_user, chat_id, room_id, visited_id)
    # チャットしている相手を取得し、通知を送る
    temp_ids = Chat.select(:user_id).where(room_id: room_id).where.not(user_id: current_user.id).distinct
    temp_ids.each do |temp_id|
      save_notification_chat!(current_user, chat_id, temp_id['user_id'])
    end
     # もしチャットが空だったら、投稿者に通知を送る
    save_notification_chat!(current_user, chat_id, visited_id) if temp_ids.blank?
  end

  def save_notification_chat!(current_user, chat_id, visited_id)
    # チャットは複数回することが考えられるため、複数回通知する
    notification = current_user.active_notifications.new(
      chat_id: chat_id,
      visited_id: visited_id,
      action: 'chat'
    )
    # 自分のチャットの場合は、通知済みとする
    if notification.visitor_id == notification.visited_id
      notification.checked = true
    end
    notification.save if notification.valid?
  end
app/models/user.rb
 # フォロー通知
  def create_notification_follow!(current_user)
    temp = Notification.where(["visitor_id = ? and visited_id = ? and action = ? ",current_user.id, id, 'follow'])
    if temp.blank?
      notification = current_user.active_notifications.new(
        visited_id: id,
        action: 'follow'
      )
      notification.save if notification.valid?
    end
  end

コントローラー作成

$ rails g controller notifications
app/controllers/notifications_controller.rb
class NotificationsController < ApplicationController
  def index
    @notifications = current_user.passive_notifications.page(params[:page]).per(20)
    @notifications.where(checked: false).each do |notification|
      notification.update_attributes(checked: true)
    end
  end
end

通知一覧表示
見たら未読false→既読trueと変わるよう指定

ルーティング

config/routes.rb
 resources :notifications, only: :index

ビュー

部分テンプレート

app/views/notifications/_notification.html.erb
<% visitor = notification.visitor %>
<% visited = notification.visited %>

<div class='m-2'>
  <%= link_to user_path(visitor) do %>
    <span class="visitor_user_image_box"><%= attachment_image_tag visitor, :image, class:"visitor_user_image", fallback: "logo.png" %></span>
    <%= visitor.nickname %>
  <% end %>
  <span>さんが</span>

  <% case notification.action %>
    <% when 'follow' then %>
      <%= "あなたをフォローしました" %>
    <% when 'chat' then %>
      <%= link_to 'あなたにメッセージ', chat_path(notification.visitor), style:"font-weight: bold;", class: "border-bottom" %>
      <%= "を送りました" %>
  <% end %>
  <span><%= " (#{time_ago_in_words(notification.created_at)}前)" %></span><br>
</div>
app/views/notifications/index.html.erb
<div class="text-center">
  <% notifications = @notifications.where.not(visitor_id: current_user.id) %>
  <!--自分の投稿に対するいいね、コメントは通知に表示しない-->

  <% if notifications.exists? %>
    <%= render notifications %>
    <%= paginate notifications %>
  <% else %>
   <p>通知はありません</p>
  <% end %>
</div>

未読の通知があることを知らせる

app/views/layouts/application.html.erb
<% if unchecked_notifications.any? %>
  <span>
    <i class="fas fa-circle n-circle"></i>
  </span>
<% end %>
<%= link_to "通知一覧", notifications_path %>

・fas fa-circle(fontawesome)
・n-circle(CSSで色付け color: #efa04c;)

0
1
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
0
1