rails内(簡易チャットアプリ)でjavascriptを使った際にエラーが出た時の対処フロウ【自分用】

## 簡易チャットアプリ(rails)で起こったJSのエラー
[![Image from Gyazo](https://i.gyazo.com/0d188d6f1414f78de448c78264cc0fb9.gif)](https://gyazo.com/0d188d6f1414f78de448c78264cc0fb9)
①非同期通信でメッセージを送信すると、current_userの名前が「undefined」になる。
②imageがnullの時、ビューに表示されないための条件式(三項演算子)を以下のように書いたにも関わらず、imageが表示されてしまう。

~~~message.js
function buildHTML(message) {
    var image = message.image ? `<img class="message-text__image" src=${message.image}>` : "";

    var html = `<div class='message'>
                  <div class='message-info'>
                    <div class='message-info__name'>
                      ${message.name}
                    </div>
                    <div class='message-info__date'>
                      ${message.created_at}
                    </div>
                  </div>
                  <div class='message-text'>
                    <p class='message-text__content'>
                      ${message.content}
                    </p>
                      ${image}
                  </div>
                </div>`
    return html;
  }
~~~

しかし、リロードするとちゃんと表示される。

③メッセージを更新するためのアクションをapp/controllers/api/messages_controller.rb内に実装し、それをリクエストされるように、message.js内でreloadMessagesという名前の関数にして、呼び出すようにした。

しかし、failメソッドが作動しconsoleにはerrorが表示される。

~~~message.js
var reloadMessages = function () {
    //カスタムデータ属性を利用し、ブラウザに表示されている最新メッセージのidを取得
    var last_message_id = $('.message').last().data("id");
    console.log(last_message_id)
    var group_id = $(".current-group").data("group-id");
    console.log(group_id)
    $.ajax({
        //ルーティングで設定した通りのURLを指定
        url: '/groups/' + group_id + '/api/messages',
        //ルーティングで設定した通りhttpメソッドをgetに指定
        type: 'get',
        dataType: 'json',
        //dataオプションでリクエストに値を含める
        data: {
          id: last_message_id
        }
      })
      .done(function (messages) {
        console.log('success');
      })
      .fail(function () {
        console.log('error');
      });
  };
  reloadMessages();
~~~

[![Image from Gyazo](https://i.gyazo.com/364b34c12c8ebc50c5b739beb2445b20.png)](https://gyazo.com/364b34c12c8ebc50c5b739beb2445b20)

## 実際にデバッグ作業をしてみる
### ①リロード前の非同期通信で起こるメッセージ送信後のエラーなので、message.jsを確認する。
~~~message.js
$(function () {
  function buildHTML(message) {
    var image = message.image ? `<img class="message-text__image" src=${message.image}>` : "";

    var html = `<div class='message'>
                  <div class='message-info'>
                    <div class='message-info__name'>
                      ${message.name}
                    </div>
                    <div class='message-info__date'>
                      ${message.created_at}
                    </div>
                  </div>
                  <div class='message-text'>
                    <p class='message-text__content'>
                      ${message.content}
                    </p>
                      ${image}
                  </div>
                </div>`
    return html;
  }
  $('#new_message').on('submit', function (e) {
    e.preventDefault();
    var formData = new FormData(this);
    var url = $(this).attr('action')
    $.ajax({
        url: url,
        type: "POST",
        data: formData,
        dataType: 'json',
        processData: false,
        contentType: false
      })
      .done(function (data) {
        console.log(data)
        var html = buildHTML(data);
        $('.messages').append(html);
        $('.messages').animate({
          scrollTop: $('.messages')[0].scrollHeight
        }, 'fast');
        $(".form__submit-btn").prop('disabled', false);
        $("#new_message")[0].reset();
      })
      .fail(function (data) {
        alert('error');
      });
  });

  var reloadMessages = function () {
    //カスタムデータ属性を利用し、ブラウザに表示されている最新メッセージのidを取得
    var last_message_id = $('.message').last().data("id");
    console.log(last_message_id)
    var group_id = $(".current-group").data("group-id");
    console.log(group_id)
    $.ajax({
        //ルーティングで設定した通りのURLを指定
        url: '/groups/' + group_id + '/api/messages',
        //ルーティングで設定した通りhttpメソッドをgetに指定
        type: 'get',
        dataType: 'json',
        //dataオプションでリクエストに値を含める
        data: {
          id: last_message_id
        }
      })
      .done(function (messages) {
        console.log('success');
      })
      .fail(function () {
        console.log('error');
      });
  };
  reloadMessages();
});
~~~
ビューを表示しているのは、message.jsの「var html = buildHTML(data);」および、呼び出し元の「function buildHTML(message)の箇所。

バッククオート（``）を使ったテンプレートリテラル記法で書かれたHTML内の、式展開(${})に送られているデータが怪しそうと判断。データ元は「$('#new_message').on('submit', function (e)」の中にあるdoneメソッドの引数のdata。

~~~message.js
.done(function (data) {
  console.log(data)
  var html = buildHTML(data);
  $('.messages').append(html);
~~~

~~~message.js
function buildHTML(message) {
    var image = message.image ? `<img class="message-text__image" src=${message.image}>` : "";

    var html = `<div class='message'>
                  <div class='message-info'>
                    <div class='message-info__name'>
                      ${message.name}
                    </div>
                    <div class='message-info__date'>
                      ${message.created_at}
                    </div>
                  </div>
                  <div class='message-text'>
                    <p class='message-text__content'>
                      ${message.content}
                    </p>
                      ${image}
                  </div>
                </div>`
    return html;
  }
~~~

### ②console.logでdataの中身を確認
「.done(function (data) {」にすぐ下にconsole.log(data)を記述。引数にdataを入れることで、dataの中身を確認。

~~~message.js
.done(function (data) {
  console.log(data)
  var html = buildHTML(data);
  $('.messages').append(html);
~~~
chromeのデベロッパーツールで、consoleを確認すると...

[![Image from Gyazo](https://i.gyazo.com/c6248921afeeeab0ef51dad9ba68cb74.png)](https://gyazo.com/c6248921afeeeab0ef51dad9ba68cb74)

[![Image from Gyazo](https://i.gyazo.com/4f522eafaba208ff12eccc8b4bb6b0be.png)](https://gyazo.com/4f522eafaba208ff12eccc8b4bb6b0be)

dataは取得されていた。それぞれのキーバリューのキーの名前と、message.js内のビューを表示している部分を見比べると、「user_name」が${message.name}とドットの後の名前が違っていた。

~~~message.js
function buildHTML(message) {
    var image = message.image ? `<img class="message-text__image" src=${message.image}>` : "";

    var html = `<div class='message'>
                  <div class='message-info'>
                    <div class='message-info__name'>
                      ${message.name}  
                    </div>
~~~

create.json.jbuilderの名前を確認してみる。すると、user_nameを変数名にしていた！

~~~create.json.jbuilder
json.(@message, :content, :image)
json.created_at @message.created_at
json.user_name @message.user.name
json.id @message.id
~~~

create.json.jbuilderの「user_name」を「name」にしても直るが、「user_name」の方が他の人が見ても分かり易く親切。

なので、message.jsの式展開の方を「${message.name}」から「${message.user_name}」に変更して、①の問題は完了。

[![Image from Gyazo](https://i.gyazo.com/04e6158208c5582072e9ac491e4b9932.gif)](https://gyazo.com/04e6158208c5582072e9ac491e4b9932)

### ③imageが表示されないように条件式を書いている箇所を確認
続いて、②のimageがnullの時、ビューに表示されないための条件式(三項演算子)を以下のように書いたにも関わらず、imageが表示されてしまう問題。

~~~message.js
var image = message.image ? `<img class="message-text__image" src=${message.image}>` : "";
~~~

consoleで先ほど同様、doneメソッド内に送られているdataを見てみる。

[![Image from Gyazo](https://i.gyazo.com/ab003828296932fd9cf16d208e9c40a1.png)](https://gyazo.com/ab003828296932fd9cf16d208e9c40a1)

imageの中にはurlがある...。つまり、三項演算子で書かれたif文では、「message.image」となっているので、trueが返ってきてしまう。正しくは「message.image.url」のように、messageの中のimageの中にurl中に値がある場合の条件にする。

~~~message.js
 var image = message.image.url ? `<img class="message-text__image" src=${message.image.url}>` : "";
~~~

これで②の問題は解決。

### ④.failメソッドが動いているので非同期通信はうまくいっている。dataを送っているコントローラーが怪しい

一応、変数の「var last_message_id」と「var group_id」の下にそれぞれconsole.logを置いたが、値は送られていた。

doneメソッドにdataをjson形式で送っているapp/controllers/api/messages_controller.rbのindex下にbinding.pryを記述し、paramsの中身をターミナルで確認する。

~~~app/controllers/api/messages_controller.rb
class Api::MessagesController < ApplicationController
  def index
    binding.pry
    @group = Group.find(params[:group_id])
    @messages = @group.messages.where('id > ?, params[:last_message_id]')
    respond_to do |format|
      format.json
    end
  end
end
~~~

~~~
[9] pry(#<Api::MessagesController>)> params
=> <ActionController::Parameters {"id"=>"284", "format"=>"json", "controller"=>"api/messages", "action"=>"index", "group_id"=>"37"} permitted: false>
~~~
app/controllers/api/messages_controller.rbのwhereメソッドで記入している「:last_message_id(最新のメッセージ)」が無いことが確認。ターミナル内の「"id"=>"284"」が本来whereメソッド内に書くべきキーだった。

なので、「params[:last_message_id]」を「params[:id]」に変更した。

binding.pryの記述を消して、ブラウザを確認してみるもまだerrorが出る。

[![Image from Gyazo](https://i.gyazo.com/31ce00c0e28c51286f44670d14a32823.png)](https://gyazo.com/31ce00c0e28c51286f44670d14a32823)

### ⑤consoleのエラーURLを開いてエラーを確認
[![Image from Gyazo](https://i.gyazo.com/a3776b58bd6be2c1f2f2e4909901ed81.gif)](https://gyazo.com/a3776b58bd6be2c1f2f2e4909901ed81)

エラー文を確認すると、mysqlでsyntaxエラー(構文エラー)が起こっていることがわかった。

~~~
ActiveRecord::StatementInvalid in Api::Messages#index

Showing /Users/riku27/projects/chat-space/app/views/api/messages/index.json.jbuilder where line #1 raised:
Mysql2::Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?, params[:id])' at line 1: SELECT `messages`.* FROM `messages` WHERE `messages`.`group_id` = 37 AND (id > ?, params[:id])
~~~

その中でも以下のエラー文に注目すると、(id > ?, params[:id])が値に置き換えされていないのがわかる。

~~~
at line 1: SELECT `messages`.* FROM `messages` WHERE `messages`.`group_id` = 37 AND (id > ?, params[:id])
~~~

それを踏まえて、app/controllers/api/messages_controller.rbのwhereメソッドをよくみると...

~~~app/controllers/api/messages_controller.rb
@messages = @group.messages.where('id > ?, params[:id]')
~~~

本来、where('id > ?', params[:id])のように、id > ?のみをシングルクォーテーションで囲わないといけないところ、params[:id]まで囲ってしまったので、文字列として認識されてしまっていた。

これを修正して、全ての問題解決。

## デバックをする上でこういう風に考えろと言われたこと
①databaseにデータを渡す前に起こったエラー(DBには保存されていない)なのか
②databaseにあるデータをもらった時に起こったエラーなのか(主にコントローラーに原因ある)

でDBを見て線引きする。

##　最後に
僕が教えてもらったことを自分用メモとして、覚えている範囲で殴り書きしました。かなりまとまりが悪くなってしまっているので、読んでいただいた方には申し訳ないと思います！