非同期通信でメッセージ送信する方法について

非同期通信の実装においての理解をアウトプットしてみた。

#非同期通信でメッセージ送信とは？
身近な例で言えば、LINEでメッセージを送信した際、送信したメッセージが画面の下にスクロールする動作がそれに当たる。

#実装手順

1.フォームが送信されたら、イベントが発火するようにする
2.イベントが発火したときにAjaxを使用して、messages#createが動くようにする
3.messages#createでメッセージを保存し、respond_toを使用してHTMLとJSONの場合で処理を分ける
4.jbuilderを使用して、作成したメッセージをJSON形式で返す
5.返ってきたJSONをdoneメソッドで受取る
6.doneメソッドで受取り、HTMLを作成する
7.作成したHTMLをメッセージ画面の一番下に追加し、その分メッセージ画面を下にスクロールさせる
8.非同期に失敗した場合の処理も準備する
9.完成ソースコード

1.フォームが送信されたら、イベントが発火するようにする

```javascript

$("#new_message").on('submit', function(e) {
      e.preventDefault();
      var formData = new FormData(this);
      var url = $(this).attr('action');
})
```
new_message であるフォームが送信されたら、イベントが発火する。


2.イベントが発火したときにAjaxを使用して、messages#createが動くようにする

```javascript

$.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
      })
```
以上のように、ajax通信を行って、」コントローラのcreateアクションを動かす。


3.messages#createでメッセージを保存し、respond_toを使用してHTMLとJSONの場合で処理を分ける

messages_controller.rb

```ruby

def create
    @message = @group.messages.new(message_params)
    if @message.save
        respond_to do |format|
            format.html {redirect_to group_messages_path(@group), notice: 'メッセージが送信されました'}
            format.json
        end
    else
        @message = @group.message.includes(:user)
        flash.now[:alert] = 'メッセージを入力してください'
        render :index
    end
end
```
以上のように、respond_to do |format| を使い、コントローラーのcreateアクション内で、formatがHTMLの時とjsonの時との処理を分ける。

4.jbuilderを使用して、作成したメッセージをJSON形式で返す

create.json.jbuilder

```javascript

json.user_name    @message.user.name
json.content    @message.content
json.time    @message.created_at
json.id    @message.id
```

5.返ってきたJSONをdoneメソッドで受取る

```javascript

      .done(function(data){
        var html = buildHTML(data);
        $('.messages').append(html);
        $('.form__message').val('');
        $('.form__submit').prop('disabled', false);
        $('.messages').animate({ scrollTop: $('.messages')[0].scrollHeight});
      })
      .fail(function(){
        alert('error')
        $('.form__submit').prop('disabled', false);

```

6.doneメソッドで受け取ったHTMLを作成する

```javascript

$(function() {
  function buildHTML(message){
  var html = `<div class="message">
                <div class="upper-message">
                    <div class="upper-message__user-name">
                        ${ message.user_name }
                    </div>
                    <div class="upper-message__date">
                        ${ message.time }
                    </div>
                </div>
                <div class="lower-message">
                    <p class="lower-message__content">
                        ${ message.content }
                    </p>
                </div>
             </div>`
      return html; 
  }
    })
  })
})
```

7.作成したHTMLをメッセージ画面の一番下に追加し、その分メッセージ画面を下にスクロールさせる

```javascript

 .done(function(data){
        var html = buildHTML(data);
        $('.messages').append(html);
        $('.form__message').val('');
        $('.form__submit').prop('disabled', false);
        $('.messages').animate({ scrollTop: $('.messages')[0].scrollHeight});
      })
```
スクロールさせる時は、animateとscrollHeightのメソッドが必要となる


8.非同期に失敗した場合の処理

```javascript

.fail(function(){
        alert('error')
        $('.form__submit').prop('disabled', false);
```
連続でメッセージを送信しようとすると、エラーメッセージがアラートされる


9.完成ソースコード

```javascript

$(function() {
  function buildHTML(message){
  var html = `<div class="message">
                <div class="upper-message">
                    <div class="upper-message__user-name">
                        ${ message.user_name }
                    </div>
                    <div class="upper-message__date">
                        ${ message.time }
                    </div>
                </div>
                <div class="lower-message">
                    <p class="lower-message__content">
                        ${ message.content }
                    </p>
                </div>
             </div>`
      return html; 
  }

  $("#new_message").on('submit', function(e) {
      e.preventDefault();
      var formData = new FormData(this);
      var url = $(this).attr('action');
      $.ajax({
      url: url,
      type: "POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
      })
      
      .done(function(data){
        var html = buildHTML(data);
        $('.messages').append(html);
        $('.form__message').val('');
        $('.form__submit').prop('disabled', false);
        $('.messages').animate({ scrollTop: $('.messages')[0].scrollHeight});
      })
      .fail(function(){
        alert('error')
        $('.form__submit').prop('disabled', false);
    })
  })
})

```

以上、ざっくりとした解説でした。細かいコードの意味までは、まだ全然理解できていないので、どなたかご指摘いただけると助かります。

以上