🍐

Rails 非同期通信のコメント機能にエラーメッセージを表示

2023/05/08に公開

はじめに

非同期通信でのコメント機能は実装済みです!
https://zenn.dev/goldsaya/articles/968b2441342357

「401字以上のコメント」はNGというバリデーションをかけて、
そこにエラーメッセージ自体も非同期で表示できるようにします!🏋🏻

1.バリデーション

app/models/post_comment.rb
class PostComment < ApplicationRecord
  belongs_to :user
  belongs_to :book

+ validates :comment, presence: true, length: { maximum: 400 }
end

一応マイグレーションファイルも編集

db/migrate/20xxxxxxxx_create_post_comments.rb
class CreatePostComments < ActiveRecord::Migration[6.1]
  def change
    create_table :post_comments do |t|
+     t.text :comment, null: false
      t.integer :user_id, null: false
      t.integer :book_id, null: false

      t.timestamps
    end
  end
end
app/views/post_comments/_form.html.erb
<div class="mt-3">
    <%= form_with model: [ book, post_comment ], local: false do |f| %>
      <%= f.text_area :comment, placeholder: "コメントをここに",required: true, class: "w-100" %><br>
      <%= f.submit "送信" %>
    <% end %>
  </div>

ここまでの記述で空欄の投稿に対しては以下のように表示されます。
しかし、401文字打ってもバリデーションには引っかかるものの何も出てこないという状況です。

2.コントローラー

コントローラーで保存できなかった場合の記述を書きます!

コメントが(バリデーションに引っかかってしまい)保存されなかったら、
render 'error' が読み込まれます💡

app/controllers/post_comments_controller.rb
class PostCommentsController < ApplicationController
  def create
    @book = Book.find(params[:book_id])
    @user = @book.user
    @post_comment = current_user.post_comments.new(post_comment_params)
    @post_comment.book_id = @book.id
+   unless @post_comment.save
+     render 'error'
+   end
  end
ifとunlessの違い

ifとunlessは条件分岐に使われるキーワードであり、基本的には反対の条件を表します。

ifは、条件がtrueの場合に処理を実行し、falseの場合は処理をスキップします。
一方、unlessは条件がfalseの場合に処理を実行し、trueの場合は処理をスキップします。

3.render先の記述(error.js.erb)

views/post_comments/error.js.erb
$("#comments-error").html("<%= j(render 'layouts/errors', obj: @post_comment) %>");

コメントが401字でバリデーションに引っかかっているので、saveメソッドがfalseを返し、
@post_commentの持ってる値としては”false"になっています。

$("#comments_error")でid = "comments_error"をターゲットとし、render 'layouts/errors'で指定しているlayouts/_errors.html.erbの内容で書き換えています。

ちなみにlayouts/_errors.html.erbの中身はこんな感じ
layouts/_errors.html.erb
<% if obj.errors.any?%>
<div class="text-center" style="color:red;">
<%=obj.errors.count %>件のエラーが発生しました。<br>
<% obj.errors.full_messages.each do |message| %>
    <%= message %>
  <% end %>
</div>
<% end %>

4.エラーメッセージを表示させる

先ほどのエラー文を表示させるために、id = comments-errorを差し込む!

app/views/post_comments/_form.html.erb
+<div id ="comments-error"></div>
  <div class="mt-3">
    <%= form_with model: [ book, post_comment ], local: false do |f| %>
      <%= f.text_area :comment, placeholder: "コメントをここに",required: true, class: "w-100" %><br>
      <%= f.submit "送信" %>
    <% end %>
  </div>

<div id ="comments-error"></div>という箇所を作成しました。
これでコメント欄のすぐ上にエラーメッセージを表示されます!!

非同期通信のエラーメッセージ表示の流れ

コメントがバリデーションに引っかかり保存されない

errorのjsファイルに飛ぶ

jsファイルは指定されているidにhtml以下を差し込む

該当のidが記載されている箇所で、html以下を受け取り表示する

普段は
<div id ="comments-error"></div>なっているところが、
エラーになると
<div id ="comments-error">render 'layouts/errors', obj: @post_comment</div>
になってくれて、エラー文が表示される!

エラーメッセージの消去

エラーメッセージが表示された後に、新しい投稿をしてもエラーメッセージが消えない問題が発生したのでコードを追加しました!

create.jsに、comment-errorのlengthがあった時に、
comments-errorを消す記述を追記!

app/views/post_comments/create.js
$("#post-comments").html("<%= j(render "post_comments/show", book: @book) %>");
$("#comment_count").html("<%= @book.post_comments.count %>")
$("textarea").val('');
+if ($("#comments-error").length) {
+  $("#comments-error").remove();
+}

これで、新しいコメントが投稿された際に、エラーメッセージが残らなくなりました💪🏻

🌱empty()メソッドとremove()メソッドの違いについて
https://techtechmedia.com/empty-remove-jquery/

🌱参考にさせていただいた記事

https://qiita.com/ki_87/items/7263ce8b7b3f26ca279b

https://qiita.com/nakachan1994/items/a7d0957afa9dfd9146ed

https://qiita.com/jackie0922youhei/items/4f53047489cff3471f66


ややこしい〜〜〜が、
非同期通信について少し理解が深まったかも?

地道に積み重ねて理解していこう🏋🏻

Discussion