Action Cableでリアルタイムコメント機能(2/2)

### ★Action Cableでリアルタイムコメント機能を実装する
新たにチャットルームは作成せずに投稿に紐づいたコメント機能として
リアルタイムでコメントの投稿、削除が可能な実装を行う

今回はリアルタイムコメント機能を実装する
下記リンクでActionCableについて少しまとめている
[コメント機能の基礎(1/2)へ](https://qiita.com/coxcoa/items/a6d41e022f4dd7d9b825)

### ❶controllerを確認する
コメントのcreateとdestroyを行った後
javascriptへデータとして送りたい情報をここで指定する

```ruby
#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ファイルを繋げる

```ruby
#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
```
```ruby
#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で指定したものにする](https://)
[文字列の中にコードを埋め込む記法について整理](https://)



```ruby
#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>
                  &nbsp;${data.date}
                  &nbsp;<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 を入れておいて

```ruby
#_index.html.erb
<li class="comment-container" id="comment-#{comment.id}">
```
これを見つけてあげて削除をする

また、(`comment-${data.id}`)とすることで
コメントのIDのみを取得している
コントローラーで@comment.idで送信しているので、する必要はないと思うが
id：137のように137だけでなく余計な部分も送信されていたため指定を細かくした

debuggerを小まめに使い、確認しつつ実装することが重要

```ruby
#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のみで実装した