コメント機能の実装でハマった話

#投稿文に対してコメントをつける機能を実装する
**エラー文**
SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value (SQL: insert into `comments` (`body`, `updated_at`, `created_at`) values (あああああああああ, 2019-06-17 20:28:43, 2019-06-17 20:28:43))

検証①
user_idに値が設定されていないという文面。たぶんuser_idがうまくpostされてないのかな？と思った。
user_idとpost_idはcommentsテーブルの必須項目のカラム。
しかし、ブラウザでHTMLソースを見ても`<input type="hidden" name="user_id" value="{{ $user->id }}">`で値が入っている。

```show.blade.php
@extends('layouts.app')

@section('title', 'レビューページ')

@section('content')
    <div class="container mt-4">
        <div class="border p-4">
            <h1 class="h5 mb-4">
                {{ $post->title }}
            </h1>
            <div class="user-name text-right">{{ $post->user->name }}さん</div>

            <p class="mb-5">
                {!! nl2br(e($post->body)) !!}
            </p>
            @if (Auth::check())
            <form class="mb-4" method="POST" action="/post/{{ $post->id }}">
                @csrf
                <input type="hidden" name="post_id"  value="{{ $post->id }}">
                <input type="hidden" name="user_id" value="{{ $user->id }}">

                <div class="form-group">
                    <label for="body">
                        本文
                    </label>

                    <textarea
                        id="body"
                        name="body"
                        class="form-control {{ $errors->has('body') ? 'is-invalid' : '' }}"
                        rows="4"
                    >{{ old('body') }}</textarea>
                    @if ($errors->has('body'))
                        <div class="invalid-feedback">
                            {{ $errors->first('body') }}
                        </div>
                    @endif
                </div>

                <div class="mt-4">
                    <button type="submit" class="btn btn-primary">
                        コメントする
                    </button>
                </div>
            </form>
            @endif
            <section>
```

検証②
(SQL: insert into `comments` (`body`, `updated_at`, `created_at`)...
SQL文にuser_idとpost_idのカラム指定がないぞ。なんで？コントローラ内の記述にミスがないか確認。
`$params = $request->all();`の中身にuser_idとpost_idが入ってないのかな？
エラーを吐き出している処理の`Comment::create($params);`をコメントアウトして`$params`の中身を確認。
`$params`にはuser_idとpost_idを含めた正常な値が配列で表示された。


```CommentController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;
use App\Comment;

class CommentController extends Controller
{
  public function store(Request $request)
  {
      $validate_rule = [
          'post_id' => 'required|exists:posts,id',
          'body' => 'required|max:2000',
      ];
      $this->validate($request, $validate_rule);
      $params = $request->all();
      return $params;
      //Comment::create($params);
      return redirect()->route('posts_show', ['id' => $request->post_id]);
  }
}
```

検証③
値もしっかり入っててpostされているのになんでDBに保存できないんだろうか？
`Comment::create($params);`の処理を作っているモデルの方を確認する。

```Comment.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use App\Post;
use App\User;

class Comment extends Model
{
    protected $fillable =['body'];

    public function post()
    {
      return $this->belongsTo('App\Post');
    }

    public function user()
    {
      return $this->belongsTo('App\User');
    }
}

```

あれ？？`protected $fillable =['body'];`がbodyフィールドだけになっている...違和感を感じ

```Comment.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use App\Post;
use App\User;

class Comment extends Model
{
    protected $fillable =['body', 'post_id', 'user_id];

    public function post()
    {
      return $this->belongsTo('App\Post');
    }

    public function user()
    {
      return $this->belongsTo('App\User');
    }
}

```

`protected $fillable =['body', 'post_id', 'user_id];`に修正。
無事、コメント投稿された。とても時間がかかってしまった。。。

#なぜこのエラーの解決にハマったのか(時間がかかったか)
- 実行されたSQL文を勘違いしていた。値が取得できていないからuser_idとpost_idのカラム指定がないと思っていた。
- `$params`の中身を確認する方法が最初わからなかった。
- 勘や予測を頼りにデバッグしていた。

**デバッグは勘や読みに頼りすぎず、観察することを優先する。原因を切り分け順序を追って一つ一つ潰していくこと。効率のよいデバッグ方法は順を追って観察すること。**
#今後の対策として実行
- ログにSQLクエリを出力させて、普段から見るようにした。