😎

[Rails]非同期でコメント機能実装

2023/02/05に公開

非同期に欠かせないajaxについてから

※ここは前回も少し書いたので知ってたら読み進めてもらって大丈夫!

ajax

"Asynchronous JavaScript + XML"の略。
(=> JavaScriptがAjaxを構成する中核になるよ。)
Asynchronous = 非同時性の、非同期のの意味。
「JavaScriptとXMLを使って非同期にサーバとの間の通信を行うこと。」

ajaxは一つの機能ではなく、複数が組み合わさっている!

一つの機能でできているのではなく、以下のような複数の機能が組み合わさって実装している。

  • XML
  • JavaScript
  • DOM
  • XML

ajaxの処理の流れ

  1. JavaScriptの組み込みオブジェクトである,XMLHttpRequestを使用し,更新に必要な一部のデータだけをサーバーにリクエストする。XMLHttpRequestについて:ドキュメントはここ

XMLHttpRequest:サーバーと対話するために使用され、これがあることで、ページの再読み込みなしで直接サーバーにリクエストを送信する事が出来る。

2. XMLファイルを使用し、レスポンスを返す。

XML:クライアントとサーバー間で情報をやりとりする際に、使用されるマークアップ言語

?:なんでHTMLではなくXML??=> リクエストで、XMLHttpRequestオブジェクトを使用しているため。⚠️JSONも可能!

3. DOMを使用し、書き換える場所を指定する

DOM:Document Object Modelの略.APIの一つで、HTMLやXMLをプログラムで操作する事が出来る。

これをMVCモデルに当てはめて、処理の違いをわかりやすくすると…

MVC形式 MVC js形式
1 ブラウザからhtml形式のリクエスト ブラウザからjs形式のリクエスト
2 ルーティングがどこのCのアクションか判断 ルーティングがどこのCのアクションか判断
3 コントローラにてアクション内の項目を実行 コントローラにてアクション内の項目を実行
4 アクションに応じてモデルの内容を更新、削除、インスタンスの取得 アクションに応じてモデルの内容を更新、削除、インスタンスの取得
5 app/views/コントローラ名/アクション名.html.erbを探し出し、レンダリング app/views/コントローラ名/アクション名.js.erbを探し出し、レンダリング

js形式の方はjsの働きで部分的にviewをレンダリング。viewごとにはレンダリングしない。

非同期コメント機能の実装方法

今回の制作してるものはこちら。

この赤枠で囲った部分を非同期化していきます。

1. jQueryの記述

<Gem file>

gem 'jquery-rails'

記入したら必ず、bundle install すること。

2. 非同期したい部分を部分テンプレート化する


青線のように分けて作っていきます。

※コメント数のカウントのところは今は何もしなくて大丈夫!

<_commentslist.html.erb>

<% book.book_comments.each do |book_comment| %>
<p>
<%= link_to users_path(book_comment) do %>
  <%= image_tag book_comment.user.get_profile_image, size:'50x50' %>
  <%= book_comment.user.name %>
<% end %> 
<%= book_comment.created_at.strftime('%Y/%m/%d') %>
<%= book_comment.comment %> 

  <% if book_comment.user == current_user %>
    <%= link_to "Destroy", book_book_comment_path(book_comment.book, book_comment), method: :delete,class: "btn btn-sm btn-danger",remote:true, data: {"turbolinks" => false} %>
  <% end %>

<% end %> 
</p>	

delateのlink_to部分には、非同期対応にするために
remote:true, data: {"turbolinks" => false}を追記

<_form.html.erb>

<%= form_with model: [book, book_comment], local: false do |f| %>
  <%= f.text_area :comment, rows: '5', style: "width:100%",placeholder: "コメントをここに" %>
  <%= f.submit "送信" %>
<% end %>

form_withlocal: falseを追記

3. idをつける

作成したらrenderを記述するが、そこにIDをつける


:
省略
:
:

       <td>
      <div>コメント件数:<span id="comment_count"><%= @book.book_comments.count %></span></div>
    </td>    
   </tr>  
 </table>
        
      <div id="book-comments">
        <%= render "book_comments/commentslist", book: @book %>
      </div>
       
      <div id="comment-form">
        <%= render "book_comments/form", book: @book,book_comment:@book_comment %>
      </div>

上記でpartialしなかったが必要だったコメント件数の部分があるが、そこにもidをつける

4. コントローラーのredirect先を削除

class BookCommentsController < ApplicationController
  def create
    @book = Book.find(params[:book_id])
    @comment = current_user.book_comments.new(book_comment_params)
    @comment.book_id = @book.id
    @comment.save
    #redirect_to book_path(@book)
   end


  def destroy
    @comment = BookComment.find(params[:id])
    @comment.destroy
    @book = Book.find(params[:book_id])
    #redirect_to request.referer
  end
 
   private
   def book_comment_params
     params.require(:book_comment).permit(:comment)
   end	      

redirect先を消すことによって、そのアクション名のjsファイルを探しにいくようになる!

5. アクション名と一緒のjs.erb作成,記述

destroy.js.erb

$('#book-comments').html("<%= j(render "book_comments/commentslist", book: @book) %>");
$('#comment_count').html("<%= @book.book_comments.count %>")

create.js.erb

$('#book-comments').html("<%= j(render "book_comments/commentslist", book: @book) %>");
$('#comment_count').html("<%= @book.book_comments.count %>")
$("textarea").val('');

ここでは jQueryの記述方法になっています

<jQuery の基本型>

 $(“セレクタ”).メソッド(“パラメータ[引数]”);

ここでは、$(“”)の部分にidを入れることでそこの部分を呼び出し、
.html("");の部分で、後悔はhtmlメソッドを使用しているので、HTMLに対して何をするか、どうするかを()内に記述していく。今回はアクションがあった後表示したい部分を記載するといいから、以上のようになる。

コメント数のカウント部分に関しては、両方に共通することなので、両方のファイルに
$('#comment_count').html("<%= @book.book_comments.count %>") で記述。

createの部分に関して、コメント作成後は削除機能も含めているコメント一覧部分へコメントを表示させたいので、
$('#book-comments').html("<%= j(render "book_comments/commentslist", book: @book) %>");
追加後は、boxをカラにしたいので、$("textarea").val('');です。


以上!

Discussion