どんなプログラミング言語でもそうですが、効率の良いデバッグの方法を探すことがとても大事です。

Rails を使う場合は強力なデバッガーである byebug(pry-byebug)がありますので、これの使い方を是非覚えましょう。

byebug と pry-byebug の違い

この話をする時は irbpry について触れないといけないのですが、話が少々ややこしいので 3行で説明をすると...

  • pry は irb の後継
  • byebug は irb 上で動くもの
  • pry-byebug は byebug を pry上で動くようにしたもの

となります。

これだけ見ると byebug より pry-byebug 使った方がいいんじゃないかといった印象持ちます。

実際今まで(2019年ぐらいまで)は Rails使う時は irb より pry を使う方が一般的な感じだったので、byebug より pry-byebug を使う方が多かった印象です。

ところが Ruby v2.7 から標準でついている irb が高性能になってきていて pry じゃなくてもいいんじゃないかみたいなところが出てきてます。

Ruby v2.7 での変更点について ↓
https://qiita.com/jnchito/items/ff89392f46cc9d500c94#シンタックスハイライトや自動インデントなどirbが大きく進化した

こういった事情もあるので、この記事では byebug のベースに説明をしていきます。

微妙にコマンドの違いはあるものの、考え方的に大きな違いはないです。
byebug は Rails の Gemfile に標準で入っていますが、pry-byebug 入っていないので自分で追加する必要があります。)

できること

  • 任意の場所でプログラムの処理を止められる
  • 止めた場所から 1行ずつ動作確認ができる

この 2 つが大きいです。

任意の場所でプログラムの処理を止められる

任意の場所でプログラムを止めることを、「ブレークポイントを追加する」と言います。

ブレークポイントがプログラムがストップする場所のことです。

byebug を使う場合 debugger というコマンドを使うことで、ブレークポイントを追加することができます。(※ pry-byebug は binding.pry

そして止めた時点での変数の状態を確認することができるので、意図した通りに動いてくれないとき、どこの値がおかしいのかを簡単に探ることができます。

「フォームで入力した値がうまくデータベースに保存されない」

といったケースを考えます。

view

image
こんな感じのフォームで「Create Task」ボタンをクリックするとリクエストが送信されます。

リクエストを受付けるところは tasks_controller#create です。

# POST /tasks
# POST /tasks.json
def create
  # ↓ ここに追加 ↓
  debugger
  # ↑ ここに追加 ↑

  @task = Task.new(task_params)

  respond_to do |format|
    if @task.save
      format.html { redirect_to @task, notice: 'Task was successfully created.' }
      format.json { render :show, status: :created, location: @task }
    else
      format.html { render :new }
      format.json { render json: @task.errors, status: :unprocessable_entity }
    end
  end
end

すると...

[23, 32] in /rails_todo_sample/app/controllers/tasks_controller.rb
   23:
   24:   # POST /tasks
   25:   # POST /tasks.json
   26:   def create
   27:     debugger
=> 28:     @task = Task.new(task_params)
   29:
   30:     respond_to do |format|
   31:       if @task.save
   32:         format.html { redirect_to @task, notice: 'Task was successfully created.' }
(byebug)
(byebug)

rails s コマンドを実行した時に表示されるサーバーのログに、こんな感じで表示されて処理が止まります。

これは 28 行目の @task = Task.new(task_params) を実行する前の状態、ということです。

この場所はすでに controller の中にいるので、変数 params の中身を確認することができます。

そこで params と入力して view からリクエストされたパラメータの状態を確認してみます。

(byebug) params
<ActionController::Parameters {"authenticity_token"=>"xxxxxx", "task"=>{"name"=>"New Task Name", "description"=>"説明文"}, "commit"=>"Create Task", "controller"=>"tasks", "action"=>"create"} permitted: false>

ここでリクエストされたパラメータの状態を確認することができるので、意図した内容が送信されているかどうかを確認することができます。

止めた場所から 1行ずつ動作確認ができる

next と入力することで、次の行に移動することができます。

下記の例は 29 行目で処理が止まっていますが、その段階では @task 変数が nil の状態です。

次に next コマンドを実行して次の行へ移動した時にもう一度 @task 変数を確認すると 28 行目の処理が実行された結果として値が入っていることが確認できます。

1 行ずつプログラムを実行することをステップ実行と言います。

ステップ実行をしながら変数の状態を確認していくことで、どこでバグが発生しているかを追いやすくなります。

[23, 32] in /rails_todo_sample/app/controllers/tasks_controller.rb
   23:
   24:   # POST /tasks
   25:   # POST /tasks.json
   26:   def create
   27:     debugger
=> 28:     @task = Task.new(task_params)
   29:
   30:     respond_to do |format|
   31:       if @task.save
   32:         format.html { redirect_to @task, notice: 'Task was successfully created.' }
(byebug)
(byebug) @task
nil
(byebug) next

[25, 34] in /rails_todo_sample/app/controllers/tasks_controller.rb
   25:   # POST /tasks.json
   26:   def create
   27:     debugger
   28:     @task = Task.new(task_params)
   29:
=> 30:     respond_to do |format|
   31:       if @task.save
   32:         format.html { redirect_to @task, notice: 'Task was successfully created.' }
   33:         format.json { render :show, status: :created, location: @task }
   34:       else
(byebug) @task
#<Task id: nil, name: "New Task Name", description: "説明文", created_at: nil, updated_at: nil>

デバッグを制する者が、プログラミングを制する

自分が書いたコードがうまく動かないという場面に出会った時にこそ、プログラマ

どれだけ技術力をつけても間違ったコードを書いてしまいます。

ましてやプログラム書き初めての頃は、うまくいかないことの方が多いかと思います。

そこで効率が良いデバッグを方法を知っておくと、その先のコードを書くスピードが段違いになるのでまずデバッグ方法を押さえておくと良いですね!!