ajaxで非同期通信。処理の流れをざっくり解説

# WHAT
ajaxを使って非同期通信をして、メッセージを画面遷移なしで投稿します。
ajaxとjbuilderの処理の流れがよくわからず、理解するのに大変苦労したので、忘れないうちに備忘録。

# WHY
ajaxとjbuilderの処理の流れがよくわからず、コードを書くのにかなり時間がかかったため。
※間違い等あれば、ご指摘ください！！

# 処理
## 1. フォームを送信


_form.html.haml

```_form.html.haml
= form_for [@group, @message], html: {class: 'msg_form'} do |f|
  = f.hidden_field :user_id, value: "#{@message.user_id}"
  = f.text_field :body, autofocus: true, placeholder: "type a message", class: "form__textfield"
  = link_to "#" do
    %i{class:"fa fa-picture-o"}
  = f.submit "Submit", class: "form__submit"
```

ルーティング（一部抜粋）

```
GET    /groups/:group_id/messages(.:format) messages#index
POST   /groups/:group_id/messages(.:format) messages#create
```

## 2. フォーム送信イベントを中止し、js処理へ

```js
$(function() {
// 省略
  $('.msg_form').on('submit', function(e) {
    e.preventDefault();
    // ここでフォームのsubmitイベントを中止。

    var api_url = window.location.pathname; 
    // ajaxでリクエストを送る際のパス取得

    var formdata = new FormData($(this).get(0)); 
    // formdataオブジェクトとして、フォームに入力した値を取得
    // 以下のコードでformdataの中身を確認できる（らしい）
    // for(item of formdata) console.log(item);


    // ajaxを使って、json形式でリクエストを送る。
    $.ajax({
      url: api_url,       // リクエストのパス。ここでは'/groups/23/messages'
      type: 'POST',       // HTTPメソッド
      data: formdata,     // リクエストと一緒に送るdata
      contentType: false, // リクエストに含まれているdataの型はこれですよ〜の記述（リクエストヘッダにあるらしい）を変更しないよ
      processData: false, // リクエストに含まれているdataの実際の型を変更しないための記述出そうだ
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　// 上記2つの指定はしないといけないらしい。
                          // 参考 : http://semooh.jp/jquery/api/ajax/jQuery.ajax/options/
      dataType: 'json',   //JSON形式でリクエスト送るよ
    })
    // ここまでで、ajaxのリクエストの指定。
    // リクエストが送信されるので、ルーティングが読まれる。

    // （以下省略）
    // うまく行ったらこう、ダメならこう、というコードが続く。
  });
});
```


## 3. コントローラー処理
2 でajaxから、HTTPメソッド'POST' で '/groups/:group_id/messages(.:format)' のリクエストが送られた。ルーティング通り messages#create （つまりmessagesコントローラーのcreateアクションが処理される。）

messages_controller.rb

```messages_controller.rb
class MessagesController < ApplicationController
  def create
    @message = Message.new(message_params) // Messageインスタンス生成
    @message.user_id = current_user.id  // paramsでは取れないuser_id, group_idを追加
    @message.group = Group.find(params[:group_id]) // MessageインスタンスにGroupをアソシエーション
    if @message.save // もしMessageインスタンスを保存できたら
      respond_to do |format| 
        format.html {redirect_to group_messages_path(params[:group_id])} 
        // リクエストがHTML形式であれば、リダイレクト
        // 今回のアプリケーションでは読まれることはない（はず）だが、一応記述

        format.json
        // リクエストがJSON形式であれば、（今回は）jbuilderを実行
        // 今回のアプリケーションでは、format.jsonが読まれるべき。
      end
    else // もしMessageインスタンスを保存できなければ
      flash[:notice] = "メッセージを入力してください"
      redirect_to group_messages_path(params[:group_id])
    end
  end

  private
  def message_params
    params.require(:message).permit(:body ,:image, :user_id).merge(group_id: params[:group_id])
  end
end
```


## 4. jbuilder処理
ajaxによりJSON形式でリクエストが読まれ、messages_controller.rbのcreateアクションが動いた。
respond_to 以下 format.json の記述により、views/messages/create.json.jbuilderが読まれる。

create.json.jbuilder

```create.json.jbuilder
json.name @message.user.name
json.body @message.body
json.image @message.image
json.group_id @message.group_id
json.user_id @message.group_id
json.time @message.created_at
```

リクエストによって送られたjson形式のdataオブジェクトに関して
nameキー には @message.user.nameがvalueとなる。
bodyキー には @message.body　
...（以下省略）

つまりdataの中身は以下のようなJSON形式のハッシュに。
.key を指定することで、それぞれのvalueを取得できるようになる。

```js
Object {name: "yukihiro", body: "ooo", image: null, group_id: 23, user_id: 23…}
```

jbuilderの処理が終わったので、message.jsの ajaxの後半へ進む。

## 5. ajax リクエストが成功/失敗した場合

```js
$(function() {
  function new_message(message) {
    var new_message = $('<div class="msg">' +
                '<p class="msg__username">'+ message.name +'</p>' +
                '<p class="msg__time">'+ message.time + '<p>' +
                '<p class ="msg__passage">' + message.body +'</p>' +
                '</div>');
    return new_message;
  }

  $('.msg_form').on('submit', function(e) {
    // 省略
    // さっきこのajaxでリクエスト送った
    $.ajax({
      url: api_url,
      type: 'POST',
      data: formdata,
      contentType: false,
      processData: false,
      dataType: 'json',
    })

    // ajaxのリクエストが成功したら.doneが読まれる
    .done(function(message){ 
      console.log('success!'); // デバッグ用
      console.log(message); // 上に同じ
      var html = new_message(message); // 非同期でメッセージを追加したかったので、これ
      $('.msg').append(html); // 実際に追加する
      // 'chat__content'の末尾に'html'を加える
      $('.form__textfield').val('');   //テキストフィールドを空にする
      $('.form__submit').prop('disabled', false);  //送信ボタンを有効にする
    })

    // ajaxのリクエストが失敗したら、.failが読まれる
    .fail(function(message){
      console.log('error!');
    });
```