LoginSignup
38
55

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-05-25

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処理へ

$(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を取得できるようになる。

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

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

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

$(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!');
    });
38
55
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
55