★Action Cableでリアルタイムコメント機能を実装する
新たにチャットルームは作成せずに投稿に紐づいたコメント機能として
リアルタイムでコメントの投稿、削除が可能な実装を行う
今回はリアルタイムコメント機能を実装する
下記リンクでActionCableについて少しまとめている
コメント機能の基礎(1/2)へ
❶controllerを確認する
コメントのcreateとdestroyを行った後
javascriptへデータとして送りたい情報をここで指定する
#comments_controller.rb
class CommentsController < ApplicationController
def create
@post = Post.find(params[:post_id])
#投稿に紐づいたコメントを作成
@comment = @post.comments.build(comment_params)
@comment.user_id = current_user.id
if @comment.save
ActionCable.server.broadcast 'message_channel', content: @comment, user: @comment.user, date: @comment.created_at.to_s(:datetime_jp), id: @comment.id,post: @comment.post
end
end
def destroy
@post = Post.find(params[:post_id])
@comment = Comment.find(params[:id])
if @comment.destroy
ActionCable.server.broadcast 'delete_channel', id: @comment.id
end
end
private
def comment_params
params.require(:comment).permit(:content, :post_id, :user_id).merge(user_id: current_user.id)
end
end
❷channelでcontrollerとjavascriptファイルを繋げる
#message_channel.rb
class MessageChannel < ApplicationCable::Channel
def subscribed
stream_from "message_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
#delete_channel.rb
class DeleteChannel < ApplicationCable::Channel
def subscribed
stream_from "delete_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end
❸javascriptでリアルタイムで実装したい処理を記述する
日時の表示をformatで指定したものにする
文字列の中にコードを埋め込む記法について整理
#message_channel.js
import consumer from "./consumer"
window.addEventListener('load', function(){
consumer.subscriptions.create("MessageChannel", {
connected() {
// Called when the subscription is ready for use on the server
},
disconnected() {
// Called when the subscription has been terminated by the server
},
received(data) {
const html = `<div id="test-${data.id}">
<p><a href="/users/${data.user.id}">@${data.user.nickname}</a></p>
<span style="font-weight:bold;">${data.content.content}</span>
${data.date}
<a id="delete-btn", data-method="delete" href="/posts/${data.post.id}/comments/${data.id}"><button id="${data.id}">削除</button></a>
</div>`;
const messages = document.getElementById('collapseExample');
const newMessage = document.getElementById('comment_content');
messages.insertAdjacentHTML('beforeend', html);
newMessage.value='';
var countComment = document.getElementsById('collapseExample').length;
console.log(countComment)
}
});
})
delete_channel.jsの流れ
コメントのコンテナ要素にあらかじめコメント ID を入れておいて
#_index.html.erb
<li class="comment-container" id="comment-#{comment.id}">
これを見つけてあげて削除をする
また、(comment-${data.id}
)とすることで
コメントのIDのみを取得している
コントローラーで@comment.idで送信しているので、する必要はないと思うが
id:137のように137だけでなく余計な部分も送信されていたため指定を細かくした
debuggerを小まめに使い、確認しつつ実装することが重要
#delete_channel.js
import consumer from "./consumer"
window.addEventListener('load', function(){
consumer.subscriptions.create("DeleteChannel", {
connected() {
// Called when the subscription is ready for use on the server
},
disconnected() {
// Called when the subscription has been terminated by the server
},
received(data) {
const test = document.getElementById(`${data.id}`)
const container = document.getElementById(`test-${data.id}`);
console.log(container)
container.remove();
},
});
})
★今回実装した削除機能の別プランは以下が考えられる
insertAdjacentHTML で要素を挿入した後、その要素に onclick イベントハンドラを追加してハンドラ内で削除のリクエストを送る
JQueryを使用すれば記述を短くできるが、今回は勉強の為にJavascriptのみで実装した