LoginSignup
5
3

More than 3 years have passed since last update.

非同期通信

Last updated at Posted at 2020-03-17

非同期通信(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 = $('

').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');
    });
  });
});
5
3
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
5
3