概要
ToDoアプリに「いいね」や「コメント」などがついた時の通知を受け取れるようになるためのコードを書いた。
前提として通知させたい機能は既に制作したものとする。
model => controller => view の順でプログラムしていこうと思う
完成イメージ
model
class CreateNotices < ActiveRecord::Migration[7.0]
def change
create_table :notices do |t|
t.references :receivor_id, foreign_key: { to_table: :users }, null: false
t.references :sender_id, foreign_key: { to_table: :users }, null: false
t.references :to_dos, null: false, foreign_key: true
t.integer :action, null: false
t.integer :action_id, null: false
t.boolean :checked, null: false
t.timestamps
end
end
references型を簡単に説明すると他のテーブルと関係性がある型である。
今回は receivor_id, sender_id は users テーブルに to_do_id は to_dos テーブルの主キーしか使えないように指定している。いろいろメリットがあるが、こうするとでもし receivor_id で指定した user がテーブル上から delete されたら receivor_id を持つ notice も削除されるようになると思う。たぶん
rails db:migrate を忘れずに
modelの詳細
receivor_id | sender_id | to_do_id |
---|---|---|
通知をうけとる user の id | 通知を送った user の id | 「いいね」されたtodo の id |
action | action_id | checked |
「いいね」か「コメント」か | 各 action のテーブルの id | ユーザーが確認したかどうか |
class Notice < ApplicationRecord
belongs_to :user
belongs_to :to_do
end
to_do.rb と user.rb には下記を追記しておく
has_many :notices, dependent: :destroy
こうすることで上記した関連した user, to_do が削除されたら notice も駆除されるようになる
これで model は終了したので controller のプログラムしていこうと思う
controller
def create
@nice = Nice.new(
user_id: session[:user_id],
to_do_id: params[:to_do_id]
)
@nice.save
@todo = ToDo.find(params[:to_do_id])
@todo.nice += 1
@todo.save
#ここから追記
notice_create_nice(@nice)
#ここまで
redirect_back fallback_location: '/'
end
private
def notice_create_nice(data)
@notice = Notice.new(
receivor_id: ToDo.find(data.to_do_id).user_id,
sender_id: session[:user_id],
to_do_id: params[:to_do_id],
action: 0,
action_id: data.id
)
# 自分投稿にいいねしたときの対処
if @notice.receivor_id == @notice.sender_id
@notice.checked = true
else
@notice.checked = false
end
# 過去にいいねしてるかどうかの確認
notice_serch = Notice.where(receivor_id: @notice.receivor_id, sender_id: @notice.sender_id, action: @notice.action, to_do_id: @notice.to_do_id)
if notice_serch.blank?
@notice.save!
end
end
controllerの詳細
ここでは「いいね」した時の通知機能だけ書いています。
もし他に追加したい通知機能がある場合は各自でプログラムしてください。
まず create は自分の好きなように書いてください
工夫した点は自分の投稿に「いいね」した時、過去に「いいね」されたかどうか
前者は、自分の投稿に「いいね」した時通知来ても「知ってるよ!」と思うので、 checked を true にして対処しました。
後者は、間違えて「いいね」を二回以上送った時に通知が来てもまたも「さっき見たわ!」と思うので、 where メソッドにて複数条件をかき確認している。
「コメント」されたときも通知を送りたい人は#過去にいいねしてるかどうかの確認のところを抜いて書けばいいと思います。
@notice.action = 1 にすることを忘れずにね
controller は終わったので view をプログラムしていこうと思う。
view
module ApplicationHelper
def notices_create
@notices = Notice.where(receivor_id: session[:user_id], checked: false)
end
end
<% notices_create %>
<% if @notices.blank? %>
<div class="home-user-alert">
<p style="padding-left: 20px;">お知らせはありません</p>
</div>
<% else %>
<div class="for-alert"></div>
<div class="home-user-alert">
<ul class="notice-ul">
<% @notices.each do |notice| %>
<%= link_to "/tasks/notice/#{notice.id}/checked" do %>
#<%= link_to "リンク" do %> <% end %> でendまでをリンク指定できる
<li class="notice-li">
<% if notice.action == 0 %>
<%= あなたの投稿が応援されました。 %>
<!-- ここでN+1問題が発生してるので直したい -->
<%= ToDo.find(notice.to_do_id).text %>
<% elsif notice.action == 1 %>
<%= あなたの投稿にコメントされました。 %>
<!-- ここでN+1問題が発生してるので直したい part2 -->
<%= Comment.find(notice.action_id).text %>
<% elsif notice.action == 2 %>
<%= あなたのコメントがポリシー違反のため削除されました。 %>
<% end %>
</li>
<% end %>
<% end %>
</ul>
</div>
<% end %>
.for-alert {
height: 12px;
width: 12px;
background-color: #3ecdc6;
border-radius: 6px;
z-index: 10;
position: absolute;
top: 45px;
right: 200px;
}
.home-user-alert {
z-index: 20;
border: black solid 2px;
border-radius: 20px;
background-color: white;
width: 280px;
max-height: 400px;
position: absolute;
z-index: 20;
right: 200px;
display: none;
overflow-y: scroll;
}
.box-active {
display: block;
}
.notice-li {
border-bottom: gray 1px solid;
padding-bottom: 4px;
padding: 8px;
}
.notice-ul a:last-child li {
border-bottom: 0px;
}
import jquery from "jquery";
window.$ = jquery;
$('.fa-bell').on('click', function() {
if($('.home-user-alert').hasClass('box-active')) {
$('.home-user-alert').removeClass('box-active');
} else {
$('.home-user-alert').addClass('box-active');
};
})
この章の詳細
最初のhelper.rbの記載だが、いつもならcontrollerに書いていますが、applicationのcontrollerが見つからなかったので今回はhelperに書いた。(正確なやり方はわからない。今後調べたい。)次にapplication.html.erbのコードだが、前章から記載しているとおり、notice.actionにてアクションを判別してからそれごとに文章を出力している。
cssとjsは好きなように書いてください。
これでベルの部分を押すと通知欄が出てくるようになりましたね。