Rails で開発する場合はまずは byebug (pry-byebug)の使い方を学ぼう
どんなプログラミング言語でもそうですが、効率の良いデバッグの方法を探すことがとても大事です。
Rails を使う場合は強力なデバッガーである byebug(pry-byebug)がありますので、これの使い方を是非覚えましょう。
byebug と pry-byebug の違い
この話をする時は irb
と pry
について触れないといけないのですが、話が少々ややこしいので 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
こんな感じのフォームで「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>
デバッグを制する者が、プログラミングを制する
自分が書いたコードがうまく動かないという場面に出会った時にこそ、プログラマ
どれだけ技術力をつけても間違ったコードを書いてしまいます。
ましてやプログラム書き初めての頃は、うまくいかないことの方が多いかと思います。
そこで効率が良いデバッグを方法を知っておくと、その先のコードを書くスピードが段違いになるのでまずデバッグ方法を押さえておくと良いですね!!