非同期通信

##非同期通信(Ajax)
画面をリロードしなくても情報が反映されるWebアプリケーションの機能です。例えばTwitterだと更新しなくても情報がされますね。
非同期通信はAjax（エイジャックス）と呼ばれます。
Ajaxでは、レスポンスのデータにJSONという形式が使われることが多いです。
##JSON
データ交換を行うためのデータ記述形式の一種です。Rubyのハッシュと同様、キーとバリューの組み合わせでデータを表現する形式です。
【例】

```xxxx.js
{user_name: "testさん", created_at: "2020-03-17T10:35:13.000+09:00", content: "これがJSONの形です", image_url: null, id: 5}
```
## 非同期通信ではJavaScriptを利用
同期通信では、フォームのinputタイプがsubmitであるボタンを押すことでリクエストを行うことができました。ボタンを押すとリクエストが送られるという挙動は、HTMLであらかじめ定められているものです。
##デフォルトアクション
HTMLの要素を操作した際に定められている挙動です。aタグのようにクリックされると、リンク先のページを開く、という挙動です。
対して、今回の非同期通信ではJavaScriptのメソッドを利用してリクエストを送ります。そのため、フォーム要素のデフォルトアクションを無効にする必要があります。
リクエストに対してのレスポンスはJSON形式で返してほしい旨をリクエストに含めます。
##コントローラでJSON形式のデータを用意する
同期通信の際は特に指定せずともHTML形式のデータを返すようRailsが動いてくれます。
非同期通信をする際は、リクエストにJSON形式で返してほしい旨の情報が含まれているため、その場合の対処をコントローラのアクションに明記する必要があります。
##レスポンスするためのJSON形式のデータを準備
同期通信ではviewsディレクトリの中に○○.html.erbという形式でHTMLのファイルを準備して置くことでレスポンスとしてHTMLを返します。
非同期通信の場合、JSONのデータをレスポンスとして返す必要があります。同期通信の際と同様viewsフォルダの中にJSON形式のファイルを作成します。この時のファイル名は、○○.json.jbuilderという形式になります。
##JavaScriptでレスポンスを受け取り、HTMLを操作してToDoを追加
非同期通信では、ページがリロードされることはありません。代わりに、レスポンスとして帰ってきたJSONのデータを利用してHTMLを操作します。
JSONのデータはユーザーが投稿したToDoのデータなので、これをToDoリストの一番後ろに付け加えるようJavaScriptを書きます。
##respond_to
「リクエストがHTMLのレスポンスを求めているのか、それともJSONのレスポンスを求めているのか」を条件に条件分岐してくれます。
【例】

```xxxx.rb
respond_to do |format|
  format.html { render ... } # この中はHTMLリクエストの場合に呼ばれる
  format.json { render ... } # この中はJSONリクエストの場合に呼ばれる
end
```
HTMLを返す場合は、該当するビューを呼びその中でデータを生成しますが、JSONを返す場合はRubyのハッシュをrenderメソッドの引数として渡すだけでJSONに変換されます。そのため、以下のようにコントローラーから直接データを返すことができます。
【例】renderというメソッドに{json: { id: @user.id, name: @user.name }}というハッシュを引数として渡しています。

```xxxx.rb
respond_to do |format|
  format.json { 
    render json: { id: @user.id, name: @user.name }
  }
end
```
## JSONでレスポンスできるように
【例】

```todos_controller.rb
def create
  @todo = Todo.create(todo_params)
  respond_to do |format|
    format.html { redirect_to :root }
    format.json { render json: @todo}
  end
end
```
respond_to doを使用し、リクエストされたformatによって処理を分けるようにします。今回はhtmlと非同期通信のためのjsonを扱うようにしました。フォーマットがjsonの時、この後jsファイル側で作成したtodo（@todo）を使用するためにrenderメソッドを使用し、作成したtodoをjson形式で返すようにします。
##JavaScriptを記載して送信時に要素を取得
今回は、todo.jsというファイルをassets/javascripts以下に作成します。
Ruby on Railsでは、アプリケーション作成時にjquery-railsというgemをインストールし、assetsディレクトリ以下のapplicaton.jsファイルで//= require jqueryこのように記述することでjQueryを読み込んでいます。
【例】todo.jsにTodoの一覧ページからフォームが送信された時に、フォームに入力された値をコンソールに出力します。

```todo.js
$(function() {
  $('.js-form').on('submit', function(e) {
    e.preventDefault();
    var todo = $('.js-form__text-field').val();
    console.log(todo);
  });
});
```
submitイベントを使い、フォーム（js-form）が送信された時に処理が実行されるようにイベントを設定します。
フォームが送信された時に、デフォルトだとフォームを送信するための通信がされてしまうので、preventDefault()を使用してデフォルトのイベントを止めます。
##非同期通信でリクエスト
処理の流れ
1.フォームの送信が行われた時にAjaxによる非同期通信を始める
フォームに入力された値を取得する
Ajaxを行う記述をする
2.TodosコントローラのcreateアクションにてTodoの保存を行う
3.処理後にjsonを返す
4.非同期通信の終了後に受け取ったjsonを利用してHTMLを構築する
5.4で構築したHTMLをViewに差し込む
【例】フォームの送信が行われた時にAjaxによる非同期通信を始めるフォームの送信が行われた時にAjaxによる非同期通信を始める

```todo.js
$(function() {
  $('.js-form').on('submit', function(e) {
    e.preventDefault();
    var todo = $('.js-form__text-field').val();
    $.ajax({   #追記〜
      type: 'POST',
      url: '/todos.json',
      data: {
        todo: {
          content: todo
        }
      },
      dataType: 'json'
    })   #〜追記
  });
});
```
##$.ajax
jQueryで非同期通信を行うための記述です。.ajaxの部分がメソッドの呼び出しとなっています。
ajaxメソッドには、Rubyのハッシュのようなキーバリュー形式で引数を渡します。JavaScriptでは、このような形式のオブジェクトはオブジェクト型と呼ばれます。読みやすいように改行して縦に並べていますが、以下のようなキーとバリューの組み合わせです。
{type: 'POST', url: '/todos.json', data: { todo: { content: todo } }, dataType: 'json' }
dataというキーに対してのバリューはオブジェクト型であり、さらにそのバリューもオブジェクト型になるという、入れ子構造となっています。
Ajaxで非同期通信に必要なオプションを設定しており、それぞれの意味は以下のようになります。
type、、、HTTP通信の種類を記述する。通信方法は、GETとPOSTの2種類がある。
url、、、リクエストを送信する先のURLを記述する。
data、、、サーバに送信する値を記述する。
dataType、、、サーバから返されるデータの型を指定する。
通信方法はPOSTで、'/todos.json'というURLに{ todo: { content: todo（テキストフィールドに入力された値）} }を送信する。サーバから値を返す際は、jsonになります。

```todo.js
$(function() {
  $('.js-form').on('submit', function(e) {
    e.preventDefault();
    var todo = $('.js-form__text-field').val();
    $.ajax({
      type: 'POST',
      url: '/todos.json',
      data: {
        todo: {
          content: todo
        }
      },
      dataType: 'json'
    })
    .done(function(data) {   #追記〜
      var html = $('<li class="todo">').append(data.content);
      $('.todos').append(html);
      $('.js-form__text-field').val('');
    })
    .fail(function() {
      alert('error');
    });   #〜追記
  });
});
```
##doneとfail
ajaxメソッドの後につけることで、非同期通信が成功した際/失敗した際に行う処理を書くことができます。両方とも、ajaxメソッドとセットとなるメソッドです。doneは通信が成功したときに、failは通信が失敗したときに動きます。
##data
doneのうしろにあるdataという変数には、リクエストによって返ってきたレスポンスが代入されます。この場合のレスポンスは、非同期通信によって作成したTodoにあたります。

```todos_controller.rb
def create
  @todo = Todo.create(todo_params)
  respond_to do |format|
    format.html { redirect_to :root }
    format.json { render json: @todo}  #追記
  end
end
```
doneにもfailにも、メソッドの引数としてやってほしい処理を記述します。
今回はdoneのあとに、取得したJSONからli要素を作成しtodo一覧のリストに追加し、フォームに入力された値を空にする処理を記述しています。failのあとにはエラーが起きたことを示すアラートを表示する処理を記述しています。
最後に、htmlを生成するvar html = $('<li class="todo">').append(todo.content);という処理をメソッドにして切り出します。メソッドにして処理を分けることで、長くなりがちな処理を整理し、理解しやすくします。

```todo.js
$(function() {
  function buildHTML(todo) {   #追記〜
    var html = $('<li class="todo">').append(todo.content);
    return html;   
  }   #〜追記

  $('.js-form').on('submit', function(e) {
    e.preventDefault();
    var todo = $('.js-form__text-field').val();
    $.ajax({
      type: 'POST',
      url: '/todos.json',
      data: {
        todo: {
          content: todo
        }
      },
      dataType: 'json'
    })
    .done(function(data) {
      var html = buildHTML(data);   #追記
      $('.todos').append(html);
      $('.js-form__text-field').val('');
    })
    .fail(function() {
      alert('error');
    });
  });
});
```