DM(チャット)機能 非同期化

# はじめに
非同期化の失敗を先ほどアウトプットしていましたが、
DM機能の非同期化もまとめておきたいと思います！

# 完成物
コメントは吹き出しをつけて、送信フォームは下に固定しています！

<img width="500" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782860/d88d37fd-868e-7863-9f8d-8b5b62721029.png">

# ER図
今回は非同期化のまとめなので実装方法は割愛しますが、
こちらのER図にて実装しています

![スクリーンショット 2024-06-19 21.39.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3782860/042bc327-f2fe-fa71-6e98-9e0c60504436.png)

実装方法はこちらの記事が大変わかりやすかったです
⚠️全く同じというわけではないと思います！

https://qiita.com/mi-1109/items/660ec3630e76f11d1f16

# Viewの記述
#### テンプレートの作成
非同期化に対応したい箇所をテンプレートにします
今回の場合は、チャット一覧とチャット送信フォームです

```show.html.erb
<div class="container">
  <div class="row">
    <div class="col-sm-12 col-md-10 col-lg-8 my-3 p-4 mx-auto">
      <div class="text-center">
        <%= image_tag @user.get_profile_image(90, 90), class: "rounded-circle mx-auto d-block" %>
        <%= @user.name %>
      </div>

      <!-- チャット一覧テンプレート -->
      <div class="row chat-index mx-auto">
        <%= render 'public/chats/chats', chats: @chats %>
      </div>

    </div>
  </div>
</div>

<!-- チャット送信テンプレート -->
<div class="row mx-auto">
  <%= render 'public/chats/form', chat: @chat %>
</div>
```

#### チャット一覧のテンプレート

わかりにくいのでシンプルに表示しています！
カスタマイズしてご使用ください！

```_chats.html.erb
<% chats.each do |chat| %>
  <% if chat.user == current_user %>
    <p><%= chat.message %></p>
    <span><%= chat.created_at.strftime('%Y/%m/%d %H:%M') %></span>
  <% else %>
    <p><%= chat.message %></p>
    <span><%= chat.created_at.strftime('%Y/%m/%d %H:%M') %></span>
  <% end %>
<% end %>
```
#### チャット入力テンプレート

```_form.html.erb
<%= form_with model: chat, local: false do |f| %>

  <%= f.hidden_field :room_id %>
  <%= f.text_field :message, class: "form-control chat_textfield", placeholder: "コメントを送信" %>

  <button type="submit" class="btn btn-primary">
    <i class="fas fa-paper-plane fa-lg" style="color: #ffffff;"></i>
  </button>

<% end %>
```
:::note info
ワンポイント🌱
form_withの非同期化は `local: false`を忘れずに！
link_toを入れる場合は、`remote: true`が必要！（今回はなし）
:::

# classまたはidを付与しよう！
私は記述が長くなるのが嫌でclassに付与していますが、idでもOKです！
⚠️上記の選択で、`create.js.erb`書き方が少し異なります！

```diff_ruby
show.html.erb

      <!-- チャット一覧テンプレート -->
+      <div class="row chat-index mx-auto">
        <%= render 'public/chats/chats', chats: @chats %>
      </div>
```

```diff_ruby
_form.html.erb
<%= form_with model: chat, local: false do |f| %>

  <%= f.hidden_field :room_id %>
+  <%= f.text_field :message, class: "form-control chat_textfield", placeholder: "コメントを送信" %>

  <button type="submit" class="btn btn-primary">
    <i class="fas fa-paper-plane fa-lg" style="color: #ffffff;"></i>
  </button>

<% end %>
```

#### create.jsの作成
```view/public/chats/create.js.erb
$('.chat-index').html("<%= j(render "public/chats/chats", chats: @chats) %>");
$('.chat_textfield').val("");
```

:::note warn
注意⚠️
先ほどclassではなくidを付与した方は
`'.chat-index'`ではなく、`'#chat-index'`に修正してください
`'#chat_textfield'`も同様です！
:::

# コントローラーの修正

非同期化はjsファイルを経由して画面表示が行われるため、
通常の処理の順番と異なります
そのためcreateアクションには追記が必要です

```diff_ruby
class Public::ChatsController < ApplicationController
  def create
+    room = Room.find(params[:chat][:room_id])
+    @chats = room.chats
    @chat = current_user.chats.new(chat_params)
    @chat.save
  end
end
```

createアクション時にcreate.js.erbで@chatsを呼び出すため
この記述が必要になります！
私はここのエラーで数時間溶かしてしまいました…😨

失敗談はこちら（笑)↓
もう少し詳しくここの部分の説明をしています！

https://qiita.com/3rarara/items/a9052467b1ce02d5fa6b

# おまけ
チャットの入力フォームを下に固定する方法をついでに書いておきます！
先ほどは省略していたformのviewはこんな感じです！
このcontainerについている`fixed-bottom-form"`をcssで設定しています

```_form.html.erb
<div class="container fixed-bottom-form">
  <div class="row justify-content-center">
    <div class="col-sm-12 col-md-10 col-lg-8">
      <div class="col-md-8 mx-auto">
        <%= form_with model: chat, local: false do |f| %>
          <div class="input-group">
            <%= f.hidden_field :room_id %>
            <%= f.text_field :message, class: "form-control chat_textfield", placeholder: "コメントを送信" %>
            <div class="input-group-append">
              <button type="submit" class="btn btn-primary">
                <i class="fas fa-paper-plane fa-lg" style="color: #ffffff;"></i>
              </button>
:
```
```application.css
/*チャットフォーム*/
.fixed-bottom-form {
  position: fixed;
  bottom: 85px;
  left: 50%;
  transform: translateX(-50%);
}
```

吹き出しにする方法はこちらの記事を参考にしました！

https://qiita.com/devmatsuko/items/f72a4da3868aeda9f3a1


# さいごに
いいねやコメント、フォローの非同期化を乗り越えてきたので、
余裕かと思いきやまさかの躓きでした！
理解が深められてよかったです！

# 参照記事
参考にさせていただきました！
ありがとうございました！

https://zenn.dev/ganmo3/articles/8361e3ddc8bc86#%E5%AE%9F%E8%A3%85%E8%A6%81%E4%BB%B6

https://zenn.dev/goldsaya/articles/968b2441342357

https://qiita.com/mi-1109/items/660ec3630e76f11d1f16

https://qiita.com/devmatsuko/items/f72a4da3868aeda9f3a1