Ajaxについて【虎の巻】

### 【概要】
---
ajaxを初めてみた時になかなか処理について理解することができなかったので、思い出し確認の意味をこめて書いていこうと思います。


### 【環境】
---
この記事は下記の実行環境で動作確認しております。
・Rails 7.0.4 
・Ruby 3.1.4
・gem 'turbo-rails'

### 【補足】
---
・この記事を編集時点で、様々な気づきがありましたため、一部認識が異なる場合がございます。その場合は、ご指摘くださると幸いです。

### 【Ajaxとは】
---
例に倣って、ajaxとは。を確認していきましょう！

>Ajaxとは、AsynchronousとJavaScriptに、XMLを組み合わせて作られた造語です。先の項で紹介した非同期通信を、「JavaScriptの技術で実行すること」を指します。企業によっては、単純に「非同期通信」のことを指してAjaxと呼ぶケースもあります。AjaxはWebページに搭載されている技術ですが、このAjaxを使うことで、Webページ全体を更新することなく「一部分だけ情報を更新する」ことが可能です。Ajaxの技術そのものは古くから使用されていましたが、後述する検索エンジンや地図アプリに活用されたことで、ほかのWebページやサービスでも取り入れられるようになりました。


### 【Ajaxの実例】
---
Ajaxは様々なアプリで使用されております。代表例をあげてみましょう。
・検索エンジン
・地図アプリ(GoogleMapなど)
・ECサイト
・SNSサービス(スクロールで過去の投稿を見る・いいね機能など)

### 【Ajaxのメリット】
---
先の例で挙げたような機能を実装する際に、`パフォーマンス向上`が期待できます。具体的には

・Webページの一部分だけを更新するため、サーバ側の負担を抑える
・通信量の抑制


### 【ajax_前準備】
---
まずは実装する要件を確認します。
・gem 'turbo-rails'を使用。
・ブックマークボタンをajaxにて実装。
┗ブックマーク登録・解除を実装。
・IDをbookmark-button-for-board-掲示板IDのように定義する

では、前準備として、ajaxしたい処理の設定を行いましょう。

◇Controllerを実装◇
```ruby
<!-- app/controllers/bookmarks_controller.rb -->
class BookmarksController < ApplicationController
  def create
    board = Board.find(params[:board_id])
#idで管理しているところに注意 -> view側で設定を忘れないこと。
    current_user.bookmark(board)
    redirect_to boards_path, success: t('.success')
  end
#処理
  def destroy
    board = current_user.bookmarks.find(params[:id]).board
#idで管理しているところに注意 -> view側で設定を忘れないこと。
    current_user.unbookmark(board)
    redirect_to boards_path, success: t('.success'), status: :see_other
  end
end

  end
end
```

◇Bookmark用◇
```ruby
<!-- app/views/boards/_board.html.erb -->
#処理
  <% if current_user.bookmark?(board) %>
    <%= render 'unbookmark', { board: board } %>
  <% else %>
    <%= render 'bookmark', { board: board } %>
  <% end %>
```
◇対応するパーシャル1◇
```ruby
<!-- app/views/boards/_bookmark.html.erb -->
#省略
<%= link_to bookmarks_path(board_id: board.id), id: "bookmark-button-for-board-#{board.id}", data: { turbo_method: :post } do %>
  <i class="bi bi-star"></i>
<% end %>
```

◇対応するパーシャル2◇
```ruby
<!-- app/views/boards/_unbookmark.html.erb -->
#省略
<%= link_to bookmark_path(current_user.bookmarks.find_by(board_id: board.id)), id: "unbookmark-button-for-board-#{board.id}", data: { turbo_method: :delete } do %>
  <i class="bi bi-star-fill"></i>
<% end %>
```

ここまでの内容をajax処理として遷移させるようにします。下記からが本題です。

### 【ajax_本題】
---
ブックマークした内容をajaxにて非同期通信するまでが今回の目的ですね。
実装する際には、下記の順で実装するように考えてください。

1.create,deleteに対応するファイルを作成
2.作成したturbo_streamを定義

のようになります。順を追ってみましょう。

1-1.createに対応するファイルを作成
```ruby
touch app/views/bookmarks/create.turbo_stream.erb
#アクション名と同名のturbo_stream.erbファイルで作成。
```

1-2.destoryに対応するファイルを作成
```ruby
touch app/views/bookmarks/destroy.turbo_stream.erb
#アクション名と同名のturbo_stream.erbファイルで作成。
```

2-1.作成したcreate_turbo_streamを定義
```ruby
<!-- app/views/bookmarks/create.turbo_stream.erb -->
<%= turbo_stream.replace "bookmark-button-for-board-#{@board.id}" do %>
#replaceは要素を書き換え。
#"bookmark-button-for-board-#{@board.id}"はviewのidと同じ要素を指定。
  <%= render 'boards/unbookmark', board: @board %>
#renderで表示するパーシャルファイルを指定。
<% end %>
```
2-2.作成したdestroy_turbo_streamを定義
```ruby
<!-- app/views/bookmarks/destroy.turbo_stream.erb -->
<%= turbo_stream.replace "unbookmark-button-for-board-#{@board.id}" do %>
#replaceは要素を書き換え。
#"bookmark-unbutton-for-board-#{@board.id}"はviewのidと同じ要素を指定。
  <%= render 'boards/bookmark', board: @board %>
#renderで表示するパーシャルファイルを指定。
<% end %>
```

create_turboをサンプルとして、解説します。
まずは、turbo_stram内の`replace`というアクションについてです。

これは、`turbo_stream`で使用できるアクションの一部になります。
詳細は下記に図表を載せていますので、そちらをご確認ください。

|アクション名|アクションの機能|
|:-:|:-:|
|replace|特定の要素を置き換え。元の要素は削除され、指定されたIDやクラスに対応する新しい内容が表示|
|append|特定の要素の末尾に新しい内容を追加。|
|prepend|特定の要素の先頭に新しい内容を追加|
|remove|特定の要素を削除します。(指定されたIDやクラスに対応)|
|update|特定の要素内の内容を更新(要素自体は変更されず、その内部のコンテンツだけが更新)|
|before|特定の要素の前に新しい要素を挿入|
|after|特定の要素の後に新しい要素を挿入|

今回の`replace`は特定の要素を差し替えるという意味なので、今回の要件としてブックマークの要素を登録・削除の実装としては問題ないですね。

但し、注意点が一点あります。それは、idで管理するために`viewファイルのid`と`turbo_streamのid`を同名で定義してあげるということです。

別名で定義してしまった場合、一致するidが見つからずに対応するブックマークに登録・削除が行えなくなる可能性があります。
(ここが若干ハマった部分なので備忘録代わりで残します。)

### 【引用元】
---
Ajaxとはどういうもの？基本情報から仕組みまで詳しく解説
https://hnavi.co.jp/knowledge/blog/ajax/
猫でもわかるHotwire入門 Turbo編
https://zenn.dev/shita1112/books/cat-hotwire-turbo/viewer/turbo-streams-fetch