36
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[超 初心者 編]JS : ajaxの解説

Last updated at Posted at 2019-12-04

##まずはじめに
Ajaxとjavascriptを勉強中に簡易なrailsアプリを作りました。
その時大枠の処理の流れが大切だと感じたので今回復習も兼ねて、初心者の方にもわかりやすいように解説してみようと思います。

大枠の流れを理解していると**エラーが起きた際にどこでデバッグしてどの変数の中身を見たら良いか、どこまでは処理がうまく書けているか。**という原因特定をする際に非常に便利です。

むしろ流れをわからないとエラー解決は手探りでの作業となってしまい非効率です。

##作ったアプリ内容

検索フォームからDBに保存してあるユーザー情報を表示する

アプリGIF
https://gyazo.com/ac90a773abec869ddb72d59037f62f46

[したいこと]
検索フォームにキーワードを入力された毎にユーザー検索して該当するユーザー名を表示する

[必要な手段]
・検索フォームに入力されたら反応
・フォームに入力されたキーワードを取得
・コントローラでキーワードを元にユーザーテーブルを検索
・検索結果をビューで表示する

#対象者
大まかな処理がわからない or 流れについて説明できる自信がない方に対してザックリと理解できるようにまとめました。

この記事では、javascriptを使ったAjax通信とは、
どのようにして送信先を決めているのか
送ったデータはどのように処理されているのか
どのように処理したデータを返すのか
エラーで詰まってしまった際にどう対処するのか
を学びます。

よって概ね同じようなAjax通信の流れを組む、インクリメンタルサーチや非同期通信、自動更新の実装にもこの記事で紹介する処理の流れやデバッグの方法は応用できます

極力専門的な言い方や記述を省き、イメージしやすいように言い回しも変えています。

#開発環境
Rails: 5.0.7.2
ruby: 2.5.1
jquery-rails: 4.3.3
mac: Mojave(10.14.4)

#まずは登場ファイルの紹介
・ edit.html ----------------- HTMLファイル(ビューファイル)

edit.html
<input class="name-form" placeholder="検索したいユーザー名" type="text">

<div class='append-user'>

・ test.js -------------------- JavaScriptファイル

test.js
$(function(){       //以下の処理を読み込ませるための必須記述
    $(".name-form").on("keyup", function() {
        //this = $(".name-form")
        var input = $(this).val();
        
        $.ajax({
            type: 'GET',                //type     = HTTPメソッドを指定する
            url: '/users',              //url      = パス(URI or Prefix)を指定する
            data: { keyword: input },   //data     = コントローラへ送りたいデータ
            dataType: 'json'            //dataType = コントローラが返すファイルの形式
        })
        //変換完了
        .done(function(datas) {
            if (datas.length !== 0) {   //検索にヒットした情報が1件以上だったら
                //返されたjsonデータの個数分処理を繰り返す
                datas.forEach(function(data) {
                    //一人一人のユーザー情報(data)をブラウザに表示する任意のメソッド
                    appendHTML(data);
                });
            }
        })
        //変換失敗
        .fail(function() {
            alert('失敗しました');
        })
    });
});

・ users_controller.rb -------- コントローラファイル

users_controller.rb
class UsersController < ApplicationController
    def index
        return nil if params[:keyword] == ""
        @users = User.where(['name LIKE ?', "%#{params[:keyword]}%"] ).where.not(id: current_user.id).limit(10)

        # ajax通信の記述:dataTypeの種類に応じて参照するファイルを切り替える
        respond_to do |format|
            format.html
            format.json
            # ajax記述には、dataType: 'json' と書かれているので
            # index.json.jbuilderファイルが読み込まれる
        end
    end
end

・ index.json.jbuilder --------- json.jbuilderファイル

index.json.jbuilder
json.array! @users do |user|
    json.id   user.id
    json.name user.name
end

#処理の流れ目次[記事内リンク]

項番 ページ内リンク
1 ビューファイルが読み込まれる
2 ビューと同時にJavaScriptファイルも読み込まれる
3 2-1. ここで一旦test.jsファイルは何をしてくれるファイルなのかを解説
4 イベントを発火させる
5 ①関数定義が動く
6 5-1. デバッグ作業の心構え
7 ②関数が動く。ajax通信の設定
8 発火させるべきコントローラとアクションの選定方法
9 ③コントローラでの処理
10 ④json.jbuilderファイルでの変換処理
11 [⑤変換結果に応じた処理(done & fail)](#⑤変換結果に応じた処理(done & fail))
12 11-1. failメソッドが実行される場合
13 11-2. doneメソッド内の処理で不具合が起こった場合
14 よくある間違いへの対処

#今回のajax通信の流れ
空白ページ.png

##ビューファイルが読み込まれる
(コントローラのアクションに紐づくビューファイルが読み込まれるということ)

edit.html
<input class="name-form" placeholder="検索したいユーザー名" type="text">

<div class='append-user'>

表示されている画面
test_html.png
ブラウザに入力フォームが表示される
 
##ビューと同時にJavaScriptファイルも読み込まれる

test.js
$(function(){       //以下の処理を読み込ませるための必須記述
    $(".name-form").on("keyup", function() {

        //this = $(".name-form")
        var input = $(this).val();
        

        $.ajax({
            type: 'GET',                //type     = HTTPメソッドを指定する
            url: '/users',              //url      = パス(URI or Prefix)を指定する
            data: { keyword: input },   //data     = コントローラへ送りたいデータ
            dataType: 'json'            //dataType = コントローラが返すファイルの形式
        })

        //変換完了
        .done(function(datas) {

            if (datas.length !== 0) {   //検索にヒットした情報が1件以上だったら
                //返されたjsonデータの個数分処理を繰り返す
                datas.forEach(function(data) {
                    //一人一人のユーザー情報(data)をブラウザに表示する任意のメソッド
                    appendHTML(data);
                });
            }
        })

        //変換失敗
        .fail(function() {

            alert('失敗しました');
        })
    });
});

###ここで一旦test.jsファイルは何をしてくれるファイルなのかを解説
※1行目のfunctionの記述はJSファイルを読み込ませる必要最低限の記述のため解説割愛

JavaScriptファイルは、簡単に言ってしまうと**「ビューファイルを監視して処理を実行してくれる」**ファイルです。

qiita記事素材_-_Google_スライド.png

画像の①関数を定義しておくとオレンジの範囲の処理を行なってくれます。
オレンジの範囲には②処理や②と関係する③・④の処理、⑤の処理が含まれています。

② → ③ → ④ → ⑤の順番で処理が進んでいきます
 
 
ではどんな時に①関数が動き出すのか?

これは①関数の最初に書かれている記述から読み取ることができます。

.js
$(".name-form").on("keyup", function() {

直訳
クラス名name-formの入力フォームにキー入力されそのキーが離された瞬間に動き出す関数

解説
①:$(".name-form")  読み込んだHTMLファイルの中でclass= "name-form"の要素
②:.on              
③:"keyup"          キーアップされたら(入力時のキーを離したら) 

 
 
クラス名「name-form」といえば、
edit.html.hamlで生成した入力フォームのことですね。
test_html.png

このフォームに入力がされたら、関数が動くという仕組みです。

つまり、test.jsの$(".name-form").on("keyup", function() {という記述が、現在読み込まれているビューファイルの特定のクラス名の要素の「動き」を監視しているという言い方もできるわけです。

test_html.png

 
また、記述の各部分には名称がついているので、人へ伝える時や調べものをするときに下記のワードを用いて理解を深めましょう。

.js
$(".name-form").on("keyup", function() { 処理 }

名称:セレクタ
$(".name-form")・・・「動き」を監視する対象や要素

名称:イベントハンドラ
.on・・・セレクタに対して

名称:イベント
"keyup"・・・予め検知したい「動き」を定義する(例:キーアップイベントが発生したら)

名称:無名関数
function() { 処理 }・・・セレクタに検知したい「動き」が起こったら{処理}を行う
 
 
$(セレクタ).on(イベント名, イベントが発生したときに実行する処理)

 
ちなみに、JavaScriptファイル内で「$」マークで始まる記述はJavascriptのライブラリの一つである「jQuery」の記述です。
もちろんイベントには「送信されたら」、「クリックされたら」などたくさんの種類があるので
「jQuery イベントハンドラ」でググってみましょう

jQueryイベント一覧 わかりやすい記事
http://www.jquerystudy.info/reference/events/index.html
 
 
test.jsファイルの解説は一旦終了です。

##イベントを発火させる
登場するファイルと処理の順番
【edit.html】 → ブラウザで入力操作 → 【test.js】

それではいよいよtest.jsに書かれた①関数を動かします。

そのために入力フォームへ何か文字を入力するんでしたね

ほい
test_html.png

これで定義していた処理が実行されます
 
 

##①関数定義が動く
登場するファイルと処理の順番
【test.js①】 → 【test.js②】

qiita記事素材_-_Google_スライド.png

入力イベントに反応して上記画像の1番上のfunction{}関数内の処理が実行されていきます

qiita記事素材_-_Google_スライド.png

もちろん処理は上から下へ実行されるので②ajax通信の処理ブロックにたどり着くまでに書かれている記述を実行していきます。

途中にある

.js
var input = $(this).val();

この記述は、変数inputに対してjQueryの記述で値を代入しています。

$マークのカッコで囲んだものはjQueryオブジェクトとして扱うのでしたね!
ではカッコの中に記述されているthisとは何かというと

現在処理されているfunctionのセレクタを指します。

※thisは使う場面によって色々な状態の情報が取得できるので一概に取得できる情報を明言できません。
 
 
 
①関数(function)内でthisと書くとfunctionのセレクタである$(".name-form")が取得できます
「ajax通信の流れとデバッグのやり方_初心者編_」を編集_-_Qiita.png

よって「this」は**書く場所によって結果が違う。**ということです
qiita記事素材_-_Google_スライド.png

この後解説するdone関数やfail関数のfunction内でthisを記述すると①関数内でthisを書いた時の情報とは違う状態の情報がthisの記述で取得できます

###デバッグ作業の心構え

this情報の確認方法について、ここで一旦デバッグ作業の仕方についてサクッと解説です。
this情報の確認は簡単で、確認したい場所でconsole.log(this)を記述するだけです。
例で下の画像のように3箇所にconsole.log(this)を記述します
qiita記事素材_-_Google_スライド.png

上記画像のようなconsole.log(this)の配置で様々な状況下のthisの値がコンソール画面で確認できます。

注意:console.log(〇〇)と書いたあとは①関数を動かす必要があるので必ずキーアップイベントを起こす必要あり。
ChatSpace.png

console.log()とはlogカッコ内に記述した変数の中身をブラウザの検証の「console」画面に表示するメソッドです。

定義しておいた変数などをlog引数に記述すると変数の中身がコンソール画面に表示することができ、処理に使う変数が期待する値かどうかを確認するときに大活躍します。

.js
var num = 10 + 5;
console.log(num);

//コンソール画面には「15」と表示される

この作業こそ、まさに**「デバッグ」**ですね!!

デバッグ作業の重要なポイントとしては
①変数の中身を確認する(どの変数を確認すべきか)
②変数の中身を予想する(期待する答えを考える)

この2点です!

たったコレだけですが、この2点ができるできないで作業効率は大きく変わります
普段こういったことを考えないで闇雲にデバッグしている人は、めちゃくちゃ損してます。

以上、デバッグの心構えでした。
 
 
 

では、話は戻って

.js
var input = $(this).val();

この記述は

.js
var input = $(".name-form").val();

上記のように考えることができます。
.val()は対象のvalue属性の値を取得するので
現状入力フォーム(クラス名name-formのHTML要素)には「a」が入力されているので

.js
var input = "a";

と考えることができます。
 
 
 

##②関数が動く。ajax通信の設定
登場するファイルと流れ
【test.js②】 → ③【users_controller.rb】

qiita記事素材_-_Google_スライド.png

変数inputを定義した状態で次に②関数のajax通信の設定が実行されます。

ここでのajax通信は、railsのMVCの流れに割り込んだ形でビュー(HTML)ファイルからコントローラファイルへデータを渡すために記述されています。

通常のMVCの流れ
無題のプレゼンテーション_-_Google_スライド.png

ajax通信を用いたMVCの流れ
空白ページ.png

この流れでファイルを読み込んでいきます。

ajax通信の設定は以下の内容で実行されます

.js
$.ajax({
    type: 'GET',                //type     = HTTPメソッドを指定する
    url: '/users',              //url      = パス(URI or Prefix)を指定する
    data: { keyword: input },   //data     = コントローラへ送りたいデータ
    dataType: 'json'            //dataType = コントローラが返すファイルの形式
})

ajax通信の項目
typeurlはルーティングに渡す情報を指定
dataはルーティングが判断したコントローラファイルに渡す情報の指定
ここで先ほど定義したinput変数を使っています。
dataTypeはdata項目を送ったり送り返してもらう際の通信形式を指定(値はjsonやhtmlなどが存在)

ここでもajax通信のイメージを掴んでもらうために、たとえを用いると
ajax通信とは、「外国へ荷物を配達してくれる郵便屋さん」みたいな存在です。
ちょっとよく分からないとは思いますがこのまま読み進めてみてください。(きっとわかるようになると思います)

②関数が動くと郵便屋さんが配達の準備を始めます

.js
$.ajax({
    type: 'GET',                //type     = 目的地情報その1
    url: '/users',              //url      = 目的地情報その2
    data: { keyword: input },   //data     = 送る荷物
    dataType: 'json'            //dataType = 発送方法
})

上記の情報をもとに目的地の設定や送る荷物の中身を決めます。

無題のプレゼンテーション_-_Google_スライド.png

実行されたajax通信はまずルーティングに解析され、ルーティングではHTTPメソッドはGET、パスは/usersとして判断され
users_controller.rbファイルのindexアクションが実行されます。

##発火させるべきコントローラとアクションの選定方法
ここで大事なのは発火させたいコントローラとアクションは何であるのかイメージしておくことです。

まず、なぜコントローラのアクションを発火させたいのでしょうか?
それは、コントローラではDBの情報を取得・登録・編集・削除などのアクションが実行でき、今まさにDBの情報を取得したいからです。

まずは行いたい処理を大枠で思い出しましょう。

・したいこと
DBからキーワードに該当するユーザーを取得する

・そのための手段
ajax通信を使う
キーアップされたごとに検索する
入力されたキーワード情報を取得する
キーワード情報をコントローラへ送る

では「したいこと」を実行するために最適なコントローラとは?
答えは簡単です。関係性のあるコントローラを選べば良いのです。

例えば
・users_controller.rb
・groups_controller.rb
・messages_controller.rb
と3つのコントローラがあったら、コントローラそれぞれの役割を思い出します。

・users_controller.rb:ユーザーに関わることを操作する
・groups_controller.rb:グループに関わることを操作する
・messages_controller.rb:メッセージに関わることを操作する

「したいこと」はユーザー情報の取得です。

こう考えると、users_controller.rbの一択ですね。

では次に、users_controller内のどのアクションを発火させるか?
これも7つのアクションからひとつ当てはまるものを選べば良いのです。冷静に考えれば楽勝です
当てはまるものがわからなければ目的とは異なるものを排除していきましょう!

・index・・・・・・一覧表示
・new・・・・・・新規作成画面
・create・・・・・DBに新規作成
・show ・・・・・・詳細画面
・edit・・・・・・・編集画面
・update・・・・・DBに編集内容を保存
・delete ・・・・・DBから削除

すでに登録されているユーザー情報を取得する。という観点だけでも、
・index
・show
の2つに絞られます。

・index・・・・・・一覧表示
・new・・・・・・新規作成画面 → ユーザーを新規作成するわけではない
・create・・・・・・DBに新規作成 → ユーザーを新規作成するわけではない
・show・・・・・・詳細画面
・edit・・・・・・・編集画面 → 既存のユーザー情報を書き換えたいわけではない
・update・・・・・DBに編集内容を保存 → 既存のユーザー情報を書き換えたいわけではない
・delete ・・・・・DBから削除 → ユーザー情報を削除したいわけではない

ここで重要なのは、キーワード検索して該当したユーザー情報を全て取得するという部分がポイントです。
「a」と検索したら「aaa」さんも「abc」さんの情報も該当する情報一覧を取得したいということです。

indexは一覧情報。対して
editは一人のユーザー情報の詳細です。

だからindexアクションが適切です。

users_controller#indexアクションです

これで発火させたいコントローラとアクションが選定できました!

ターミナルで「rails routes」コマンドを打って表示される一番右端に書いてあるコントローラとアクションに紐づくパスとHTTPメソッドを確認してみましょう!

railsにてページの遷移を行うには何かしらのコントローラのアクションを発火させなければいけません。
その場合、必ず「したいこと」を言語化し、発火させたいコントローラとアクションを決めてから細かい処理を組み立てていきましょう

では話を戻して、
(以下一部重複)
無題のプレゼンテーション_-_Google_スライド.png

実行されたajax通信はまずルーティングに解析され、ルーティングではHTTPメソッドはGET、パスは/usersとして判断され
users_controller.rbファイルのindexアクションが実行されます。

その後はjson.jbuilderファイル→ test.jsファイルの⑤処理というふうに処理がされていきます。
qiita記事素材_-_Google_スライド.png

郵便屋さんがdataという荷物をコントローラに渡し、コントローラはもらったdataを使って変数を生成します。最後に郵便屋さんがコントローラで生成された変数をdataの送り主(test.js)に届けるという流れです。

通常は荷物を届けた時点で郵便屋さんの仕事は終了ですが、今回はお届け先から送り主に対して送り返す荷物(情報)が発生するというお仕事になります。

一旦はこんなイメージで見ててください

 
##③コントローラでの処理
登場するファイルと流れ
③【users_controller.rb】 → ④【index.json.jbuilder】

users_controller.rbファイルのindexアクションではDBのusersテーブルからブラウザの入力フォームに入力された「a」のワードに該当するユーザー情報を@usersに代入しています。

※大枠の処理の流れが重要のため、コントローラ内の処理詳細は割愛します。

users_controller.rb
class UsersController < ApplicationController
    def index
        return nil if params[:keyword] == ""
        @users = User.where(['name LIKE ?', "%#{params[:keyword]}%"] ).where.not(id: current_user.id).limit(10)

        # ajax通信の記述:dataTypeの種類に応じて参照するファイルを切り替える
        respond_to do |format|
            format.html
            format.json
            # ajax記述には、dataType: 'json' と書かれているので
            # index.json.jbuilderファイルが読み込まれる
        end
    end
end

上記で記述されているparams[:keyword]とは
ajax通信の設定で記述したdata項目(送る荷物)のハッシュデータが深く関わってきます。
params[:keyword]とは、data項目に定義したハッシュのキー名を指定してバリューとなるinput (入力ワード「a」)を取得する記述です。

.js
data: { keyword: input },   //data     = コントローラへ送りたいデータ

なぜ送ったdataparamsに取り込まれているのか

ajax郵便屋さんが言語の違う「外国」へ行っていることを思い出してイメージしましょう
qiita記事素材_-_Google_スライド.png

日本語がアメリカでは通じないように、javascript語をrubyの言語内では使えないのでjsonという通信方法を使ってruby語の会話であるparamsに情報を混ぜてもらっているのです。

そうすると、javascript語で書いた情報でもruby国に籍を置くusers_controller.rbファイルでも読み取ることができるようになり、

test.jsから受け取った変数inputの中身を使ってDBからユーザー情報を検索できるのです。

また、検索結果を代入した@users変数はtest.js(javascript)ファイルにてユーザー検索結果を表示する際に使われる重要な変数です。
 
 
 
コントローラでtest.js(javascript)ファイルに送り返す変数@usersを定義できたら、通常のMVCの流れ同様コントローラ → ビューと処理が移るのですが、
無題のプレゼンテーション_-_Google_スライド.png

ビューファイルの参照前に、ajax通信の設定で記述したdataTypeの値に応じて参照するファイルを選定する記述がコントローラには書かれています。

users_controller.rb
respond_to do |format|
   format.html
   format.json
end

今回はdataType: jsonでajax通信を行なっていますよね

test.js
$.ajax({
    type: 'GET',                //type     = HTTPメソッドを指定する
    url: '/users',              //url      = パス(URI or Prefix)を指定する
    data: { keyword: input },   //data     = コントローラへ送りたいデータ
    dataType: 'json'            //dataType = コントローラが返すファイルの形式
})

なので**「コントローラで処理されたアクション名.jsonファイル」**の
views/users/index.json.jbuilderファイルが読み込まれます。

※respond_toの記述がなければ、コントローラで処理されたアクション名.htmlファイルが参照されます。
 
##④json.jbuilderファイルでの変換処理
登場するファイルと流れ
④【index.json.jbuilder】 → 【test.js⑤】
qiita記事素材_-_Google_スライド.png

index.json.jbuilderファイルではコントローラで生成した変数@users変換処理を行います。
qiita記事素材_-_Google_スライド.png

ん?

なぜ変換するの?と思うかもしれませんが

コントローラで生成した変数ということは、ゴリゴリのruby語で書かれた情報ということになり、
このままの状態で変数をtest.js(javascript)ファイルへ持ち帰っても誰も解読できないよね。ということになります。

 
そこで荷物を届けに来るときにjson → paramsと変換した時同様に、
送り返す際もparams → jsonと変換をしてあげます。

index.json.jbuilder
json.array! @users do |user|
    json.id   user.id
    json.name user.name
end

一つ一つ解説すると、まず始めの記述

.json.jbuilder
json.array! @users do |user|

これは変数@usersをruby言語でいうeach文で取り出しているような書き方ですね!
いわゆる繰り返し処理です。

なぜ繰り返すかというと変数@usersは複数情報が格納されている配列情報だからです。
配列情報とは1個以上の複数情報から成り立っています。

 

今回のコントローラでの処理では入力ワード「a」に該当するユーザー情報が変数@usersに詰められていますが、
DBのusersテーブルにもし「abc」さんと、「aaa」さんの2人ユーザー情報が登録されていたら、どちらのユーザーも「a」という文字列を含むため、コントローラの処理で前述の2人分の情報が変数@usersに詰められてくる可能性があるからです。

そうしたら「abc」さんにも「aaa」さんにも変換処理を行なってあげないと、test.js(javascript)ファイルで変数を受け取る際に解読できなくなってしまいます。

では次に、

.json.jbuilder
#javascript語 ← ruby語
#jsonデータ ← paramsデータ
#パン ← bread

json.id   user.id
json.name user.name

この記述は左辺がjavascript語での呼び方、右辺がruby語での呼び方を定義している記述です。
左辺に定義した名前にどんなrubyの情報を定義するか。といった感じです。

試しに、

.json.jbuilder
json.n user.name

こう書けば、
javascriptファイルで◯◯.nと記述すると、ruby語でuser.nameの情報が取得できる。といった感じ
※「〇〇」はdone関数の引数名などが入る

##⑤変換結果に応じた処理(done & fail)
登場するファイルと流れ
【test.js⑤ done】 or 【test.js⑤ fail】
qiita記事素材_-_Google_スライド.png
※appendHTML関数はブラウザにユーザー情報を表示する関数です
※この記事では大枠の処理の流れをメインに解説を行うため、doneメソッド内で使われているappendHTML関数の詳細は敢えて記述せず、解説もしません。
 
 

④index.json.jbuilderファイルでの変換処理を経て、test.jsファイルに返ってきたjsonデータ。

このjsonデータには入力ワード「a」に該当するユーザー情報が詰められているのですが、
④index.json.jbuilderの変換結果によって実行される関数が分岐します。

変換結果
変換成功 → done関数
変換失敗 → fail関数

###failメソッドが実行される場合
変換失敗の際はfail関数が処理されます。
ではどのような時に変換失敗になるか
これはjson.jbuilderでの処理が以下のような時です。

NG.json.jbuilder
json.array! @users do |user|
    json.id       user.user.id     #userが重複
    json.nickname user.mickname    #カラム名の間違い or 存在しないカラム名の指定(mickname)
    json.nickname @users.nickname  #変換する変数名が違う
end

カラム名の記述ミスや存在しないテーブルの参照など、記述をよく観察すると発見できるミスが多いです。
他にもコントローラファイル → json.jbuilderへと参照させるためにコントローラ内に記述が必要なrespond_toが抜けていたりすると適切な変換ファイルが参照されずfailメソッドが実行されてしまいます。

users_controller.rb
respond_to do |format|
   format.html
   format.json
end

予めfailメソッド内にalert("通信失敗しました");などの記述を配置してfailメソッドが呼ばれてしまったタイミングを見逃さないようにしておきましょう。

json.jbuilderファイルの記述に間違いがなさそうであれば処理の流れを遡ってコントローラで定義した変数が怪しいと考えましょう

そうしたらコントローラ内にbinding.pryを記述し、処理を止めて変数名を入力して期待通りの中身か確認しましょう!
このように原因箇所を処理の流れに沿って絞っていくことが大切です。

###doneメソッド内の処理で不具合が起こった場合

変換処理に問題がなければdoneメソッドが処理されます。
さらにdoneメソッドの引数にはjson.jbuilder内で変換されたjsonデータが入ります。
今回の例でいうと

test.js
.done(function(datas) {
   処理
})

datasという引数がjsonデータです。引数名は自由に名付けられます!
注:これまでの処理順番画像のdoneメソッドの引数名が全て「data」で記述されています。ミスですsorry

この引数の中に変換されたユーザー情報が代入されています。
このdatas引数の中身を展開してブラウザにユーザー情報を表示していくのですが、

ここdoneメソッド内での処理が一番記述を間違いやすい箇所でもあるので、エラーが起こった際は
冷静にこれまでの処理の順番を遡り、確認すべき変数を見極めデバッグしていくことが求められます。

よくある間違いの原因としては、
・doneメソッドの引数であるjsonデータを配列情報として扱っていないミス
・json.jbuilderで定義していない名前を展開しようとしている
・そもそもコントローラでの処理の時点で@users変数の中身が正常ではない
@users変数を作るための材料であるinput変数の中身がすでに正常ではない

などなど、
どの原因もconsole.logやbinding.pryを使えばすぐに割り出せる内容です。

デバッグの使い分け
javascriptファイルでの変数確認 = console.log または debugger
使えるファイル例:test.jsファイル

rubyファイルでの処理停止 = binding.pry
使えるファイル例:コントローラファイル、ビューファイル、語尾に.rbと付くファイルなら大概使える
 
 
##よくある間違いへの対処

・doneメソッドの引数であるjsonデータを配列情報として扱っていないミス

このミスへの対処は下記のような
forEachメソッドで配列の各情報を取り出して個別に処理(appendHTMLなど)することを心がけましょう

test.js
.done(function(datas) {
    if (datas.length !== 0) {   //検索にヒットした情報が1件以上だったら
        //返されたjsonデータの個数分処理を繰り返す
        datas.forEach(function(data) {
            //一人一人のユーザー情報(data)をブラウザに表示する任意のメソッド
            appendHTML(data);
        });
    }
})

コントローラでの処理にもよりますが、コントローラでwhereメソッドを使って配列情報を送ることが決定している以上は該当するユーザー情報が「aaa」さん一人分の情報であろうと配列情報に変わりはありません。

よって配列情報には必ずforEachを使って個別処理を行う必要があります。
そして、ここで取り出した変数(data)に対してようやくjson.jbuilderでの変換内容を展開できます。

例:
data.id     = ユーザーのid情報を展開
data.nickname = ユーザーの名前情報を展開

またキーワード検索で何もヒットしなかった時 = 配列に何も情報が含まれて来ない時
の処理も考えておくとユーザビリティの向上に繋がります。
「該当するユーザーはいませんでした」などなど。。。
 
 

・json.jbuilderで定義していない名前を展開しようとしている

appendHTML関数でjsonデータを展開したら「Undefind」だった。

これはもう楽勝ですね。
json.jbuilderファイルをじっくり確認しましょう!!
変換名や変換内容、展開名が食い違っていないか確認しましょう!!

 
 
・そもそもコントローラでの処理の時点で@users変数の中身が正常ではない

json.jbuilderファイルの記述にミスが見当たらなければ、もう一つ処理を遡ってコントローラを確認しにいきます
binding.pryを記述してjson.jbuilderファイルで変換する変数@usersの中身を見てみましょう!

users_controller.rb
class UsersController < ApplicationController
    def index
        return nil if params[:keyword] == ""
        @users = User.where(['name LIKE ?', "%#{params[:keyword]}%"] ).where.not(id: current_user.id).limit(10)

        binding.pry   # @users変数を定義した直後に処理を止める、ターミナルに「@users」と入力して中身の確認

        respond_to do |format|
            format.html
            format.json
        end
    end
end

ターミナルに「@users」と入力する前に、
最初は間違ってもいいので、「おそらくこんな値が入っているはず」と仮説を立ててから中身を確認することが超重要です。

 
 
 
@users変数を作るための材料であるinput変数の中身がすでに正常ではない

コントローラファイル内でbinding.pryを記述して@users変数の中身を確認してもし値が崩れていたら、
尽かさずparams[:keyword]とターミナルに入力しましょう!

params[:keyword]と入力するとキーワード情報が取得できるはずです。

もしキーワード情報が取得できない場合は、test.jsのajax通信のdata項目

test.js
$.ajax({
    type: 'GET',
    url: '/users',
    data: { keyword: input },
    dataType: 'json'
})

ここの記述が原因です

input変数を定義している記述を確認しましょう
ここでもconsole.logが大活躍です。

尽かさず変数の中身を確認しましょう!

.js
var input = $(this).val();
console.log(input);

これでも値が崩れているのなら

input変数を形成するthisを確認

.js
console.log($(this));

このように処理の順番を遡って変数の中身を確認する。

もう分かってると思うんですが。。。

最初はとにかくデバッグなんです

繰り返してデバッグをしているとデバッグのポイントでもある

①変数の中身を確認する(どの変数を確認すべきか)
②変数の中身を予想する(期待する答えを考える)

これが自然と身についてきます。

まずは手を動かすこと

コツとしては、
変数や引数があったのであれば、直後にconsole.logで確認。

これでまずは手を動かしてみましょう

test.js
$(function(){
    $(".name-form").on("keyup", function() {
        var input = $(this).val();
        console.log(input);             //input変数の中身を確認

        $.ajax({
            type: 'GET',
            url: '/users',
            data: { keyword: input },
            dataType: 'json'
        })
        .done(function(datas) {
            console.log(datas);         //引数datasの中身を確認

            if (datas.length !== 0) {
                datas.forEach(function(data) {
                    console.log(data);  //引数dataの中身を確認

                    appendHTML(data);
                });
            }
        })
        .fail(function() {

            alert('失敗しました');
        })
    });
});

中身の値の崩れが発見できたら、これまでの処理の順番を遡って変数の中身を確認していきましょう

以上、ajax通信の流れでした!!

36
22
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
36
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?