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

posted at

updated at

Rails コメント機能を非同期通信(Ajax)を用いて実装したい!

はじめに

プログラミング初学者の自分用アウトプットです。
誤った知識や記述があれば教えていただけると幸いです。

開発環境

  • ruby2.6.3
  • rails6.1.4

前提条件

本を投稿するWebアプリを作成中

  • ユーザー機能実装済(Userモデル(device導入))
  • 投稿機能実装済(Bookモデル)
  • コメント機能実装済(BookCommentモデル)

やりたいこと

  • ユーザーがコメントを投稿した際に、ページをリロードせずにコメントの投稿ができる。

  • ユーザーがコメントを削除した際に、ページをリロードせずにコメントの削除ができる。

    コメント機能を使用した際に、ページを部分的に更新できるようにしたい!

実装の流れ

●jQueryを導入

Gemfile
gem 'jquery-rails'
javascript/packs/application.js
import "jquery";
$ bundle install

●viewのコメント表示部分を部分テンプレートへ変更し、投稿フォームと削除リンクをAjaxへ適応させる

_comment_list.html.erb
<%book_one.book_comments.each do |book_comment|%>
  <tr>
    <td>
      <%=link_to(user_path(book_comment.user))do%>
       <%=image_tag book_comment.user.get_profile_image(40,40)%><br>
       <%=book_comment.user.name%>
      <%end%>
    </td>
    <td>
      <%=book_comment.comment%>
    </td>
    <td>
      <%if book_comment.user==current_user%>
       <%=link_to"Destroy",book_book_comment_path(book_comment.book,book_comment),method: :delete,remote:true,class:"btn"%>
      <%end%>
    </td>
  </tr>
 <%end%>

link_toへremote: trueを追記することにより、javascript形式でリクエストを送れます。

_comment_form.html.erb
 <%=form_with(model:[book_one,book_comment],local: false) do |f|%>
  <div class="form-group">
   <%=f.text_area:comment,class:"form-control"%>
  </div>
  <div class="form-group">
   <%=f.submit"送信",class:"btn"%>
  </div>
 <%end%>

form_withへlacal: falseと記述することにより、javascript形式でリクエストを送れます。local: trueだとHTML形式となります。

javascript形式でリクエストを送ることでページをリロードせずに一部のみ変更が可能です。

●部分テンプレートの読み込み

books/show.html.erb
 <div id="comment_list">
   <%=render"book_comments/comment_list",book_one:@book_one%>
 </div>

 <div id="comment_form">
   <%=render"book_comments/comment_form",book_one:@book_one,book_comment:@book_comment%>
 </div>
books.controller.rb
  def show
    @book_one=Book.find(params[:id])
    @book_comment=BookComment.new
  end

●コントローラーのリダイレクト先を削除する

book_comments.controller.rb
  def create
    @book=Book.find(params[:book_id])
    comment=current_user.book_comments.new(book_comment_params)
    comment.book_id=@book.id
    comment.save
    @book_comment=BookComment.new
    redirect_to request.referer#←削除
  end

  def destroy
    BookComment.find(params[:id]).destroy
    @book=Book.find(params[:book_id])
    redirect_to request.referer#←削除
  end

非同期通信となった状態では、htmlファイルではなくそのアクション名のjsファイルを読み込むようになります。そのため、redirect_to文の部分を削除しました。

●js.erbファイルを作成

book_comments/create.js.erb
$(#comment_list).html("<%=j(render"book_comments/comment_list",book_one:@book)%>");
$(#comment_form).html("<%=j(render"book_comments/comment_form",book_one:@book,book_comment:@book_comment)%>");
$(#comment_form).val("");

3行目はコメントを送信した後に、フォームを空にするための記述です。

book_comments/destroy.js.erb
$(#comment_list).html("<%=j(render"book_comments/comment_list",book_one:@book)%>");

最後に

今回の実装の流れは以下の通りです。

  1. jQueryの導入
  2. 部分テンプレートの作成
  3. link_to文へremote:true、form_with文へlocal:trueを追加
  4. 部分テンプレートをrenderで読み込み
  5. js.erbファイルを作成

定義した変数の中身にどんな情報が入っているのかをしっかり理解しておくことが大切でした。
ご覧いただきありがとうございました!至らない点ありましたらコメントで教えていただけると幸いです。

参考にさせていただいたもの

[Rails]コメント機能を非同期通信(Ajax)、ついでにエラーメッセージとフラッシュメッセージも非同期化
Railsアプリに非同期通信のコメント機能を実装
初心者目線でAjaxの説明

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?