★Action Cableでリアルタイムコメント機能を実装する
新たにチャットルームは作成せずに投稿に紐づいたコメント機能として
リアルタイムでコメントの投稿、削除が可能な実装を行いました。
今回はこの実装のベースとなるコメント機能の基礎を実装します!
Action Cableでリアルタイムコメント機能(2/2)へ
★実装に必要な基礎知識
Action Cableとは
通常のRailsのアプリケーションと同様の記述で、即時更新機能を実装できるフレームワークです。実装内容としては、メッセージの保存や送信に必要なRubyのコーディングと、保存したメッセージを即時に表示させるJavaScriptのコーディングです。
Channelとは
チャネルとは、即時更新機能を実現するサーバー側の仕組みのことをいいます。
上記に示した通り、データの経路を設定したり、送られてきたデータをクライアントの画面上に表示させたりします。
Stream_fromとは、サーバーとクライアントを関連付けるメソッドです。Action Cableにあらかじめ用意されています。
broadcastとは、サーバーから送られるデータの経路のことを指します。
broadcastを介してデータをクライアントに送信します。
ClientやChannel(.js/.rb)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>
<%= 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 %>
<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>
<%= 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 %>
<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ファイルは省略します!