0
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

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

★Action Cableでリアルタイムコメント機能を実装する

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

今回はこの実装のベースとなるコメント機能の基礎を実装します!
Action Cableでリアルタイムコメント機能(2/2)へ

★実装に必要な基礎知識

Action Cableとは
通常のRailsのアプリケーションと同様の記述で、即時更新機能を実装できるフレームワークです。実装内容としては、メッセージの保存や送信に必要なRubyのコーディングと、保存したメッセージを即時に表示させるJavaScriptのコーディングです。

Channelとは
チャネルとは、即時更新機能を実現するサーバー側の仕組みのことをいいます。
上記に示した通り、データの経路を設定したり、送られてきたデータをクライアントの画面上に表示させたりします。

Stream_fromとは、サーバーとクライアントを関連付けるメソッドです。Action Cableにあらかじめ用意されています。

broadcastとは、サーバーから送られるデータの経路のことを指します。
broadcastを介してデータをクライアントに送信します。

Clientや:repeat:Channel(.js/.rb):arrow_left:Server ※イメージ

★コメント機能の基礎を実装

❶routingの記述を行う

アクションはcreateとdestroyを使用する
投稿に紐づかせたいのでpostsとネストしてあげる

#routes.rb
Rails.application.routes.draw do
  devise_for :users, controllers: { registrations: 'users/registrations' }
  root to: "posts#index"
  resources :users
  resources :posts do
    resources :comments, only: [:create, :destroy]
  end
end

❷controllerの記述を行う

投稿ページにコメントを表示させる為、comments_controllerには
コメントのcreateとdestoryに関する記述のみをする

#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

posts_controllerにはコメントを表示させる為の記述を行う
今回は投稿に詳細ページを実装しているのでアクションはshow

#posts_controller
  def show
    @post = Post.find(params[:id])
    @comment = Comment.new
    @comments = @post.comments
  end

❸viewの記述を行う

renderを利用してコメントの表示部分とコメントの投稿部分を呼び出す

#show.html.erb
   <div class="row">
     <ul>
       <li class="comment-create">
         <h3 class="text-left title">トークルーム</h3>
       </li>
       <li class="comments_area">
         <%= render partial: 'comments/index', locals: { comments: @comments } %>
       </li>
     </ul>
     <% if user_signed_in? %>
       <div id="comment-create">
         <h3 class="text-left">コメントを投稿</h3>
           <%= render partial: 'comments/form', locals: { comment: @comment, post: @post } %>
       </div>
     <% end %>
    </div>

コメント表示部分

#_index.html.erb
    <% @comments.each do |comment| %>
      <% unless comment.id.nil? %>
        <li class="comment-container" id="test-<%=comment.id%>">
          <div class="comment-box">
            <div class="comment">
              <div class="comment-nickname">
                <p><%= link_to "@#{comment.user.nickname}", user_path(comment.user.id) %></p>
              </div>
                <div id="comment-entry">
                  <span style="font-weight:bold;"><%= comment.content %></span>
                    &nbsp;<%= comment.created_at.to_s(:datetime_jp) %>
                      <% if comment.user == current_user %>
                        <%= link_to post_comment_path(comment.post_id, comment.id), method: :delete, remote: true do %>
                          &nbsp;<button id="<%=comment.id%>" id="delete-btn">削除</button>
                        <% end %>
                      <% end %>
                </div>
              </div>
           </div>
        </li>
      <% end %>
    <% end %>
<!-- コメント内容(3件目以降) ------------------------------------------------------------------>
    <div class="collapse" id="collapseExample">
      <% @comments.offset(2).each do |comment| %>
        <% unless comment.id.nil? %>
          <li class="comment-container" id="test-<%=comment.id%>">
            <div class="comment-box">
              <div class="comment">
                <div class="comment-nickname">
                  <p><%= link_to "@#{comment.user.nickname}", user_path(comment.user.id) %></p>
                </div>
                  <div id="comment-entry">
                    <span style="font-weight:bold;"><%= comment.content %></span>
                      &nbsp;<%= comment.created_at.to_s(:datetime_jp) %>
                        <% if comment.user == current_user %>
                          <%= link_to post_comment_path(comment.post_id, comment.id), method: :delete, remote: true do %>
                            &nbsp;<button id="<%=comment.id%>" id="delete-btn">削除</button>
                          <% end %>
                        <% end %>
                  </div>
              </div>
            </div>
          </li>
        <% end %>
      <% end %>
    </div>

コメントの投稿部分

#_form.html.erb
<%= form_with(model: [@post, @comment], url: post_comments_path(@post.id) ) do |f| %>
    <%= f.text_area :content, class: "input-mysize" %>
    <%= f.submit "送信", class: "btn btn-outline-dark comment-submit float-right", id:"submit_btn" %>
<% end %>

modelとmigrationファイルは省略します!

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
0
Help us understand the problem. What are the problem?