【Rails/javascript(jQuery)】投稿内容編集の非同期化

今回、投稿内容編集機能の非同期化を初めて実装してみましたので、個人的に感じたポイントをまとめさせていただきます。

それでは、まずは動画をご覧ください。
![Alt text](https://gyazo.com/e7aceded635c3e4a654d203962840645/raw)

Editボタンを押すと元の入力内容が入った状態でinputボックスが立ち上がり、内容編集後にsaveボタンを押すと、きちんと編集後の内容がビューに反映されていることがわかるかと思います。

これまで、非同期化については何度か実装したことがありましたが、メッセージの送信機能やインクリメンタルサーチに関連する機能の実装だったため、それとの比較で言うと編集機能の非同期化においては以下3点がポイントかなと感じました。

＜非同期での入力内容編集のポイント＞
①ajaxの引数にあるdataに「'_method': 'PATCH'」を設定する
②clickイベントの親要素やその兄弟要素のクラスを取得する場合、parent()やsiblings()などを組み合わせる（こちらは、hamlのEditボタンの位置次第なので、皆さまに当てはまるものではありません）
③inputボックスを元の入力内容が入った状態で立ち上げたい場合、「value='+values.content+'」を設定する

いずれのポイントも実装してしまえばそれはそうだよなという内容ではありますが、自分が実装した際は、はじめは全然思いつかなかったので、皆さまの何かの参考になれば幸いです。

```javascript:blog_edit.js

$(function() {
  var InlineEdit;
  var values = {
    id: "",
    content: "",
  }

  function reBuild(blog) {
    var html = `<div class="content__message__box"><p class="lower-message__content">${ blog.content }</p></div>`
                
  InlineEdit.removeClass('InlineEdit-active').empty().append(html);
  }

  $(document).on("click", ".content__message__InlineEdit-cancel", function () {
    reBuild(values);  
  });

  $(document).on("click", ".content__message__InlineEdit-save", function () {

    var url = location.href + "/" + values.id;
    var input = InlineEdit.find('input').val();
      $.ajax({
        url: url,
        type: "POST",
        data: {'id': values.id,
        'content': input,
        '_method': 'PATCH'} ,  // ポイント①：非同期でテキストの編集を行う場合には、'_method': 'PATCH'を使用
        dataType: 'json'
      })
      .done(function(data) {
        reBuild(data);
      })

      .fail(function() {
        alert('message edit error');
      })
  });

  $(document).on("click", ".edit_id", function () {
    InlineEdit = $(this).parent().siblings(".content__message__box"); // 「.parent().siblings(".content__message__box")」で「this（.edit_id）」の親兄弟であるcontent__message__boxクラスを取得
    values = {
      id: InlineEdit.attr("data-edit-id"),
      content: InlineEdit.find('.lower-message__content').text(),
    }
      var input_element = '<input class="content__message__InlineEdit-input" type="text" value="'+values.content+'">';  // 「value='+values.content+'」でメッセージを入れたままinputボックス立ち上げ
      var button_element = '<ul class="content__message__InlineEdit-buttons"><li class="content__message__InlineEdit-cancel"><i class="fa  fa-times"></i></li><li class="content__message__InlineEdit-save"><i class="fa fa-check-circle"></i></li></ul>';  // 編集内容のキャンセル、編集内容の保存ボタンの立ち上げ
      InlineEdit.addClass('InlineEdit-active').empty().append(input_element).append(button_element).find('input').focus();
  });
});

```

```haml:index.html.haml
.contents
  -@blogs.each do|blog|
    .content{"data-blog-id": "#{blog.id}"}
      .content__messages
        .content__message
          .content__message__box{"data-edit-id": "#{blog.id}"}
            -# カスタムデータ属性である"data-id"の値（value）としてeach文で渡された変数（blog.id）を設定
            - if blog.content.present?
              %p.lower-message__content
                = blog.content
          .content__message__info
            %p.message__upper-info__talker
              ユーザ：
              = blog.user.name
            %p.message__upper-info__date
              投稿日時：
              = blog.created_at.strftime("%Y/%m/%d %H:%M")
          
          .content__message__edit-and-delete-btn
            %p.edit_id
              Edit

            =link_to "/blogs/#{blog.id}", method: :delete, class: "delete_id" do
              Delete

      .pict
        =image_tag blog.image.url, class: 'pict__img' if blog.image.present?
```