チャットアプリでメッセージの編集と削除のAjax処理を実装する

前回メッセージの編集と削除ボタンの実装を行いました。
[チャットアプリにメッセージの編集と削除ボタンをつける(非同期通信対応版)](https://qiita.com/sakuraniumarete/items/322acb210b70e1b1dff2)
今回その続きでボタンを押した時の処理を実装しましたので、そのまとめです。

# 今回の目的
チャットアプリでメッセージの編集と削除処理をAjax処理で行う

# 完成イメージ
メッセージ編集イメージ
![メッセージ編集イメージ.gif](https://qiita-image-store.s3.amazonaws.com/0/332038/550f37a8-bb7f-5441-ff6b-64e12f0f3a5f.gif)
メッセージ削除イメージ
![メッセージ削除イメージ.gif](https://qiita-image-store.s3.amazonaws.com/0/332038/4d1b8e96-cacd-1ed1-6fd7-777ee34fd097.gif)

# 環境
ruby 2.3.1
Rails 5.0.7.2

# 今回記載すること
今回は変更したメイン部分だけ記載させていただきます。
特にcss情報などは記載しておりませんので、
他ソースは下記Githubをご参照ください。

[chat-space](https://github.com/ham357/chat-space)

# 変更点
### ルーティングとコントーラーの設定
まずはルーティングの設定です。

```config/routes.rb
  resources :groups, only: [:create, :new, :edit, :update] do
    resources :messages, only: [:index,:update,:create,:destroy]
  end
```
「updateとdestroy」の追記を行なっています。続いてcontrollerです。
今回、下記のように処理を記載しました。

```app/controllers/messages_controller.rb
  def update
    @message = @group.messages.find(params[:id])
    @message.content = params[:content]
    if @message.save
      respond_to do |format|
        format.html  { redirect_to group_messages_path(@group), notice: 'メッセージが編集されました' }
        format.json
      end
    end
  end

  def destroy
    @message =  @group.messages.find(params[:id])
    @message.destroy
  end
```
編集と削除処理の具体的な内容は下記のように行いました。

### 編集と削除処理
まずは編集処理です。
#### 編集処理
```app/assets/javascripts/message_edit.js
//メッセージ編集処理

$(function() {
  var InlineEdit;
  var values = {
    id: "",
    name: "",
    created_at: "",
    content: "",
    image:""
  }
  
  function reBuild(message) {
    var html = `<div class="message__upper-info">
    <p class="message__upper-info__talker">
      ${ message.name }
    </p>
    <p class="message__upper-info__date">
      ${ message.created_at}
    </p>
  </div><div class="message__text">`

  if (message.content!=""){
    html += `<p class="lower-message__content">${ message.content }</p>`
  }

  if (message.image!=null){
    html += `<img src='${ message.image }', class='lower-message__image'>`
  }

  html += '</div>'

  InlineEdit.removeClass('InlineEdit-active').empty().append(html);
  }  
  $(document).on("click", ".message__InlineEdit-cancel", function () {
    reBuild(values);  
  });

  $(document).on("click", ".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'} ,
        dataType: 'json'
      })
      .done(function(data) {
        reBuild(data);
      })
      
      .fail(function() {
        alert('message edit error');
      })
    
  });
  $(document).on("click", ".message__upper-info__edit-message", function () {
    InlineEdit = $(this).parents('.message');
    values = {
      id: InlineEdit.attr("data-id"),
      name: InlineEdit.find('.message__upper-info__talker').text(),
      created_at: InlineEdit.find('.message__upper-info__date').text(),
      content: InlineEdit.find('.lower-message__content').text(),
      image: InlineEdit.find('.lower-message__image').attr("src")
    }
      var input_element = '<input class="message__InlineEdit-input" type="text" value="'+values.content+'">';
      var button_element = '<ul class="message__InlineEdit-buttons"><li class="message__InlineEdit-cancel"><i class="fa  fa-times"></i></li><li class="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();
  });
});
```
#### inputボックス、編集完了ボタン、キャンセル処理ボタンの表示
各処理を説明していきます。
カーソルが乗った時に表示される編集ボタンをクリックすると
```$(document).on("click", ".message__upper-info__edit-message", function () {}```
上記処理が実行されます。内容としては、
```values```にまず変更前のメッセージ内容を保存しています。これはキャンセルになった際に元に戻すためです。
次に下記でメッセージの変更内容を入力するinputボックスの表示と編集完了ボタンとキャンセルボタンの表示を行なっています。
また```find('input').focus()```で表示したinputボックスを入力状態にしています。

```app/assets/javascripts/message_edit.js
      InlineEdit.addClass('InlineEdit-active').empty().append(input_element).append(button_element).find('input').focus();
```

#### 編集処理とキャンセル処理
```app/assets/javascripts/message_edit.js
  $(document).on("click", ".message__InlineEdit-cancel", function () {
    reBuild(values);  
  });

  $(document).on("click", ".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'} ,
        dataType: 'json'
      })
      .done(function(data) {
        reBuild(data);
      })

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

  });
```
```$(document).on("click", ".message__InlineEdit-cancel", function () {}```でキャンセル処理を、
```$(document).on("click", ".message__InlineEdit-save", function () {}```で編集処理を行なっています。
共通で```reBuild()```により、各処理後のView表示を行なっています。編集処理ではinputボックスに入力した情報を元にAjaxで更新処理を行なっています。
それに伴って「update.json.jbuilder」を下記のように作成し、処理を行なっています。

```app/views/messages/update.json.jbuilder
json.id  @message.id
json.name  @message.user.name
json.created_at  @message.created_at.strftime("%Y/%m/%d %H:%M") 
json.content  @message.content
json.image  @message.image.url
```
続いて削除処理です。

```app/assets/javascripts/message_destroy.js
$(function() {
  $(document).on("click", ".message__upper-info__destroy-message", function () {
    var deleteConfirm = confirm('削除してよろしいでしょうか？');
    if(deleteConfirm == true) {
      var message_element = $(this).parents('.message');
      var message_id = message_element.attr("data-id");
      var url = location.href + "/" + message_id;

    $.ajax({
      url: url,
      type: "POST",
      data: {'id': message_id,
      '_method': 'DELETE'} ,
      dataType: 'json'
    })
    .done(function(data) {
      message_element.remove();
    })
    
    .fail(function() {
      alert('message destroy error');
    })
  }
  });
}); 
```
処理としては```var deleteConfirm = confirm('削除してよろしいでしょうか？');```で確認のアラートを行い、
OKだった場合は削除処理を行っています。

以上です。
少しでも参考になりましたら、いいねやフォロー気軽にしていただけると励みになります！＼(^o^)／

# 参考
[jQueryで特定の要素が存在するかどうかを判別する処理](http://black-flag.net/jquery/20150324-5622.html)
[もっと便利に！jQueryでラクラクサイト制作（実践サンプル付き）
](http://gihyo.jp/design/serial/01/jquery-site-production/0017)
[jQuery Plugin For Inline Editing Of Data On The Webpage - InlineEdit.js
](https://www.jqueryscript.net/text/jQuery-Plugin-For-Inline-Editing-Of-Data-InlineEdit-js.html)