削除機能をAjax(非同期)通信で実装してみた[Rails/jQuery] + 部分テンプレートを利用する際の罠

#**はじめに**
リソースを頻繁に削除する可能性がある場合、ページを用意せずにAjaxで削除できた方がUX向上に繋がる場合がありますね。ですので、削除機能を非同期で実装しました。

また、
`Rails`で部分テンプレートを利用した際、スクリプトの埋め込み位置の問題で実装に苦戦しました。レアなケースではあると思いますが、意外と詰まるポイントでもあるかと思いますので、この記事で共有しておきます。


#**注意点/結論**
部分テンプレートの罠に関して最初に結論を述べておきます。

部分テンプレート内で書かれたタグをスクリプト（`JavaScript`）で利用する際は、本テンプレートに記述しましょう。
部分テンプレートはあくまでも管理の観点などから分けて作成されますが、コンパイルされる際には一つの本テンプレートファイルにまとめられるので、時と場合によりますが、スクリプトは本テンプレートに記述した方が吉です。
（僕は部分テンプレートに最初記述していたので、思った挙動にならず頭悩まされましたので。。）

#**イメージ**
削除ボタンを押すと画面遷移せずに、
<img width="788" alt="古川_卓弥さん_ピトミー_ソーシャル自己分析サービス.png" src="https://qiita-image-store.s3.amazonaws.com/0/269862/7d6273bf-38ee-08f3-8625-5a920c51d484.png">
下記の画像のようになります。
<img width="786" alt="古川_卓弥さん_ピトミー_ソーシャル自己分析サービス.png" src="https://qiita-image-store.s3.amazonaws.com/0/269862/32a3b0f8-5f05-ad3a-8b38-733bc0fb66fb.png">
結果表示された`削除しました`メッセージはページをリロードすると消えます。
このように非同期であってもリロードまでは表示されるよう実装することはAjaxによるUX向上をさらに高めてくれます。

それを実現すべくコードを記述したのでその点に注意しつつ下記をご参考ください。


#**ソースコード**

まずは本テンプレートファイルの中身です。

```show.html
<!-- 本当は、show.html.erbのerbファイルです。 -->

<!-- コントローラから配列で@free_questionsインスタンスを取得しているとします -->
.
.
<%= render partial: 'free_question', locals: {free_question: free_question} %>
.
.
```
次に部分テンプレートファイルに削除機能を埋め込みます。
ポイントは削除ボタン押下後操作したいブロックに**data属性を埋め込むこと**です。
これにより、特定のブロックをAjaxで操作することが可能になります。

```＿free_question.html.erb

<div class="row form" data="<%= free_question.id %>">
  .
  .
  <%= link_to '削除', free_question_path(free_question), method: "delete", class: "delete_btn", data: {free_question_id: free_question.id}, style: 'float:right;' %>
  .
  .
</div>
```
ここで、本テンプレートにスクリプトを追記します。

```show.html
<!-- 本当は、show.html.erbのerbファイルです。 -->
.
.
<%= render partial: 'free_question', locals: {free_question: free_question} %>
.
.
<script type="text/javascript">
$(function(){
  $('.delete_btn').on('click', function(e){
    e.preventDefault();
    e.stopPropagation();
    let href = $(this).attr('href');
    let free_question_id = $(this)[0].dataset['freeQuestionId'];
    $.ajax({
      type: 'DELETE',
      headers: {
        'Content-Type': 'application/json',
      },
      dataType: 'json',
      url: href,
      data: JSON.stringify({free_question_id: free_question_id}),
      success: function(res) {
        $(".row[data=" + free_question_id + "]").empty();
        $(".row[data=" + free_question_id + "]").html(
          `<span>削除しました</span>`
        );
        return false;
      },
      error: function(res) {
        return false;
      }
    })
  });
});
</script>
```
上記のスクリプトには、successの場合、ターゲットのブロックの**配下のタグを`empty()`メソッドで空にし**、**`html()`メソッドでタグを加えてます**。


最後にコントローラの中身が以下になります。

```free_questions_controller.rb
  def destroy
    @free_question = FreeQuestion.find(params[:free_question_id])
    if @free_question.destroy
      render json: { message: "Successfuly deleted" }, status: :ok
    else
      render json: @free_question.errors, status: :unprocessable_entity
    end
  end
```

#**おわりに**
非同期処理にはさまざまな書き方がありますので、コードはご参考までにみていただけると嬉しいです。

本投稿では、
**部分テンプレートを利用している**かつ**htmlテンプレートにスクリプトを直接書き込んでいる**場合は、注意が必要!というところがポイントとなります。

少しでも役に立ったという方は、いいね、よろしくお願いします(^^)

また、[takuyaninのマイページ](https://qiita.com/takuyanin)にRails, Rubyに関していくつか記事をまとめてますので、よければご参考ください。