【Ruby on Rails】投稿機能の非同期通信、ajax化

# 目標
![ajax.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/700999/471dd00f-4edd-7f23-17af-5fbd628f000f.gif)

# 開発環境
ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

# 前提
※　▶◯◯　を選択すると、説明等が出てきますので、
　　よくわからない場合の参考にしていただければと思います。

- [deviseでログイン環境構築](https://qiita.com/japwork/items/275110b810965fbdf72f)
- [ログインユーザーのみができる投稿機能](https://qiita.com/japwork/items/8dfb52121036791ac4fb)
- [投稿の編集機能（更新、削除）](https://qiita.com/japwork/items/e258ccbbe4f48ea5a3b5)


# 流れ
1 gem 'jquery-rails'を導入
2 非同期通信にしたい箇所を部分テンプレート化
3 remote: trueを記述
4 js.erbファイルを作成
5 controllerのリダイレクト先を削除

うまくいかない場合は、
ターミナルでActionView::Template::Errorが表示される場合が多く、
大体は変数の定義忘れが多いと思います。
あとはid名やrenderの記述を間違わなければ、うまくいくはずです。


# gem 'jquery-rails'を導入
```rb:Gemfile
gem 'jquery-rails'
```
```:ターミナル
$ bundle install
```
```js:app/assets/javascript/sapplication.js
//= require rails-ujs
//= require activestorage
//= require jquery 　　　　　<--追加
//= require turbolinks
//= require_tree .
```

# 部分テンプレート化、 remote: trueの追加

今回は新規投稿画面の非同期通信を行っていきます、

```erb:app/views/posts/new.html.erb
<h1>Posts#new</h1>
<span>現在ログイン中のユーザー：<%= current_user.name %></span>

<--- form_for を form_withに変更し、, data: {remote: true}を記述 --->
<%= form_for(@post, url: posts_path) do |f| %>
<--- --->

	<div>
		<%= f.label :タイトル %><br>
		<%= f.text_field :title, autofocus: true %> <-- idを追加
	</div>
	<div>
		<%= f.label :中身 %><br>
		<%= f.text_area :body %>
	</div>
	<div><%= f.submit "投稿する" %></div>
<% end %>
<table>
	<thead>
		<tr>
			<th>投稿者名</th>
			<th>タイトル</th>
			<th>本文</th>
			<th></th>
			<th></th>
			<th></th>
		</tr>
	</thead>
	<tbody>  <-- idを追加

<--- ここから --->
		<% @posts.each do |post| %>
			<tr>
				<td><%= post.user.name %></td>
				<td><%= post.title %></td>
				<td><%= post.body %></td>
				<td><%= link_to "詳細", post_path(post) %></td>
				<td><%= link_to "編集", edit_post_path(post) %></td>
				<td><%= link_to "削除", post_path(post), method: :delete %></td>
			</tr>
		<% end %>
<--- ここまでを部分テンプレート化 --->

	</tbody>
</table>
```
修正した記述が以下の通り。

```erb:app/views/posts/new.html.erb
<h1>Posts#new</h1>
<span>現在ログイン中のユーザー：<%= current_user.name %></span>
<%= form_with model:[@post], data: {remote: true} do |f| %>
	<div>
		<%= f.label :タイトル %><br>
		<%= f.text_field :title, autofocus: true, id: "text" %>
	</div>
	<div>
		<%= f.label :中身 %><br>
		<%= f.text_area :body %>
	</div>
	<div><%= f.submit "投稿する" %></div>
<% end %>
<table>
	<thead>
		<tr>
			<th>投稿者名</th>
			<th>タイトル</th>
			<th>本文</th>
			<th></th>
			<th></th>
			<th></th>
		</tr>
	</thead>
	<tbody id="post">
		<%= render 'posts/new', posts: @posts %>
	</tbody>
</table>
```
<details><summary>補足</summary>
render 'posts/new', posts: @posts　は
app/views/posts/_new.html.erbの部分テンプレートを読み込みます。
そしてローカル変数に変更したpostsに＠postsを代入します。
※その際、createとdestroyに@postsを定義する必要があります。
これは後ほど記述していきます。</details>

部分テンプレートは以下のファイルを作成し、@postsをローカル変数に変更。
削除ボタンにもremote:trueを記述。

```erb:app/views/posts/_new.html.erb
<% posts.each do |post| %>
	<tr>
		<td><%= post.user.name %></td>
		<td><%= post.title %></td>
		<td><%= post.body %></td>
		<td><%= link_to "詳細", post_path(post) %></td>
		<td><%= link_to "編集", edit_post_path(post) %></td>
		<td><%= link_to "削除", post_path(post), method: :delete, remote: true %></td>
	</tr>
<% end %>
```

# js.erbファイルを作成

```js:app/views/create.js.erb
$('#post').html("<%= j(render 'posts/new', posts: @posts) %>");
$("text_area").val("");
$("#text").val("");
```
```js:app/views/destroy.js.erb
$('#post').html("<%= j(render 'posts/new', posts: @posts) %>");
```
<details><summary>補足</summary>
$('#post').html("<%= j(render 'posts/new', posts: @posts) %>"); は
render部分のhtmlを更新するという意味です。
$("text_area").val("");　はform_withのtext_areaを空白に
$("#text").val("");　はform_withのtext_fild（idで指定済み）を空白に
html以外にもappendなども使えるのでおすすめです
</details>
# controllersのリダイレクト先を削除
```rb:app/controllers/posts_controller.rb
  def create
    @posts = Post.all  <---追加
    @post = Post.new(post_params)
    @post.user_id = current_user.id
    if @post.save
      redirect_to new_post_path  <---削除
    else
      render :new
    end
  end

  def destroy
    @posts = Post.all  <---追加
    @post = Post.find(params[:id])
    @post.destroy
    redirect_to request.referer  <---削除
  end
```
修正後。

```rb:app/controllers/posts_controller.rb
  def create
    @posts = Post.all
    @post = Post.new(post_params)
    @post.user_id = current_user.id
    if @post.save
    else
      render :new
    end
  end

  def destroy
    @posts = Post.all
    @post = Post.find(params[:id])
    @post.destroy
  end
```