remote: trueでajaxの投稿をPOSTをするよ。

## 何をしたか
Railsでアプリを作っています。タイトルの通りなのですが、`remote: true`で`ajax`の投稿ができるフォームを作りました。
初回ではないのでスルスル作れたのですが、手順や考え方がしっかり身についていないので、自分のためのノートとしてメモします。

なお、実行環境は以下の通りです。
- `Rails 5.2.3`
- `Ruby 2.6.0`

## 参考記事
実装にあたっては、以下の記事を大変参考にさせていただきました。

[【Rails】remote: trueでフォーム送信をAjax実装する方法とは？](https://pikawaka.com/rails/remote-true)

今回の手順も↑こちらとそっくりになってしまったので、丁寧な解説をみたい方は上記の記事を見ていただいた方が良いかと思います。（こちらはあくまでも、私自身のためのメモですので。。。。）

## 実装方法
### 作ったもの
[![Image from Gyazo](https://i.gyazo.com/8d390054e8182df4f839cea624837b72.gif)](https://gyazo.com/8d390054e8182df4f839cea624837b72)
今回作ろうとしたのは、こんな感じの、投稿にぬるぬるとコメントを投稿できる仕組みです。DB構造的には`posts`テーブルに紐づく`comments`がある状況です。（画像は作成中のものなので、そのうち挿げ替えるかもしれません。）

### remote: trueのフォームを作ってみる
まずは、通常通りコメントを投稿するフォームを作ってみました。なお、装飾のためのclassや、今回の実装に関係ない要素は省略しています。（以下、全てのコードで同じ）

```slim
= form_with model: [@post, @comment] do |f|
  = f.text_field :text
  = f.submit '投稿'
```
`form_with`はデフォルトが`remote: true`なので、`local: true`もついていない、非常にシンプルなフォームになっています。

### controller

```ruby:comments_controller.rb
def create
  @comment = @post.comments.build(comment_params)
  @comment.save!
end
```

controllerも非常にシンプルにしました。
なお、今回は`remote: true`の挙動確認が主な目的なので、

**1) redpond_to, formatでhtmlとjsの処理を分けること**
**2)@commentが保存できなかった時のエラーハンドリング**

は実装していません。

2)ついては別記事にしたいなとも思うのですが、実際に実装するときには上記の２点も考慮しているというのは追記しておきます。

とにかくにも、上記のcontrollerによって**jsフォーマットの`create.js.erb`が呼び出されるようになります**。
### create.js.erb

ところで、`**.js.erb`って、聞き慣れないファイル名ですよね。このファイルは何ができるかというと、（以下、先に紹介した[こちらの記事](https://pikawaka.com/rails/remote-true)からの引用です。）

> 1. ファイル内に記述したJavaScriptのコードを実行する
2. ERBタグを使用することができる
3. インスタンス変数を使用することができる

上記のことができます。便利ですね:relaxed:
なので、上記に記した、`create.js.erb`に例えば下記の様に書くと...。

```erb:comments/create.js.erb
$('.comments').append("<%= @comment.text %>");
```

それだけでこのようなビューを作ることができます。

[![Image from Gyazo](https://i.gyazo.com/0b713a6982775efab59ca4429a656b53.gif)](https://gyazo.com/0b713a6982775efab59ca4429a656b53)

まだ形は整っていないですが、ぬるぬると投稿が表示されていきますね:relaxed:

#### 補足１：投稿をする先のビューについて
なお、順番が前後してしまいましたが...。今回投稿をする**先**のビューはこの様な構造になっています。

```slim
.comments
  = render @comments
```

`.comments`クラスの下に、`@comments`の中身を展開して呼びだす構造になっていて、（←こちら、すごく端折った書き方ですので、「？？？」という方は[こちらの記事](https://qiita.com/tanutanu/items/26da2e6bf89c2464657f)をご覧ください）

先に書いたこのコードで、

```erb:comments/create.js.erb
$('.comments').append("<%= @comment.text %>");
```
`.comments`内の`@comment`群の末尾に、投稿した新しい`@comment`が足されていきます。

#### 補足２：実際に書いたコードについて
実は上記のコードだけでは、**投稿後、フォームの中に投稿したコメントが残り続けます**。そのため、実際には下記の様なコードを書いています。

```slim
= form_with model: [@post, @comment], class: 'js-comment-form' do |f| #追記
  = f.text_field :text
  = f.submit '投稿'
```

フォームに`js-comment-form`というクラスをつけ、

```erb:comments/create.js.erb
$('.comments').append("<%= @comment.text %>");
$('.js-comment-form')[0].reset();
```

テキストの追加後、`.js-comment-form`の中身をリセット（空に）しています。

### create.js.erbでのパーシャルの呼び出し
とにかくにも、これで非同期で投稿できる様になりましたので、あとはもう少し見た目をリッチにしていきたいと思います。

結論から言うと、書いたコードは下記の通りです。

```erb:comments/create.js.erb
$('.comments').append("<%= j(render 'comment', comment: @comment) %>");
```

まず、`render 'comment'`の部分で、`comments/_comment`のパーシャルを呼び出しています。

(先の**補足１**の箇所に戻りますが、今回、コメントを投稿する**先**のビューは下記の通りです。したがって`_comment`というパーシャルが存在します。)

```slim
.comments
  = render @comments
```

次に、`j`メソッドで`JavaScript`のコードをエスケープしています。この辺りは、この２記事を読んで理解を深めました。

- [【Rails】remote: trueでフォーム送信をAjax実装する方法とは？ - 部分テンプレートを呼び出して更新する](https://pikawaka.com/rails/remote-true#%E9%83%A8%E5%88%86%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%92%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%E3%81%A6%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B)
- [What does the j function in Rails do?](https://stackoverflow.com/questions/12518526/what-does-the-j-function-in-rails-do)

パーシャルの中身は、詳しくは省略しますが、大体こんな感じです。こちらは`haml`や`slim`などを使って書いてなんら問題ありません。

```comments/_comment.html.slim
div
 = アイコンの画像
 = comment.user
 div
   = comment.text
    div
      = 削除アイコン
      = 編集アイコン
```

### 完成！
ここまでの実装で、上記にあげた画像の実装を実現しています。
[![Image from Gyazo](https://i.gyazo.com/8d390054e8182df4f839cea624837b72.gif)](https://gyazo.com/8d390054e8182df4f839cea624837b72)

ちょっと苦手なところだったのですが、一段落したところで記事を書くことで、実装に関する理解を深め、ついでにリファクタリングもできました:relaxed:

これから、エラーハンドリングや編集・削除の非同期での実装も頑張っていきたいです。