debug.gemで2回目以降にブレイクポイントで処理が止まらない


こちらの記事で繰り返し同じデバッグを行うために、 `binding.b` に引数を渡す方法を説明しました。

https://qiita.com/kyntk/items/65e3747ddb3a37a61f77#%E7%B9%B0%E3%82%8A%E8%BF%94%E3%81%97%E5%90%8C%E3%81%98%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E3%82%92%E8%A1%8C%E3%81%86

これを Controllerで実行しようとしたときに、

```diff_ruby:users_controller.rb
  # GET /users/1
  def show
+    binding.b(do: 'i ;; b @user.hoge')
+
+    @user.hoge

    render json: @user
  end
```

初回はきちんと以下のように `User#hoge` にブレイクポイントが設置できたのですが、

```bash
Started GET "/users/1" for ::1 at 2023-07-07 20:59:15 +0900
Processing by UsersController#show as HTML
  Parameters: {"id"=>"1"}
  User Load (0.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?  [["id", 1], ["LIMIT", 1]]
  ↳ app/controllers/users_controller.rb:48:in `set_user'
[8, 17] in ~/git/sample-app/app/controllers/users_controller.rb
     8|     render json: @users
     9|   end
    10|
    11|   # GET /users/1
    12|   def show
=>  13|     binding.b(do: 'i ;; b @user.hoge')
    14|
    15|     @user.hoge
    16|
    17|     render json: @user
=>#0    UsersController#show at ~/git/sample-app/app/controllers/users_controller.rb:13
  #1    ActionController::BasicImplicitRender#send_action(method="show", args=[]) at ~/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/actionpack-7.0.5/lib/action_controller/metal/basic_implicit_render.rb:6
  # and 57 frames (use `bt' command for all frames)
(rdbg:#debugger) i
%self = #<UsersController:0x00000000014aa0>
@_action_name = "show"
@_lookup_context = #<ActionView::LookupContext:0x0000000111bbc5d0 @details_key=nil, @digest_cache=nil, @cache=true, @prefixes=["users", "application"], @details={:locale=>[:en], :formats=>[:html], :va...>
@_params = #<ActionController::Parameters {"controller"=>"users", "action"=>"show", "id"=>"1"} permitted: false>
@_request = #<ActionDispatch::Request GET "http://localhost:3000/users/1" for ::1>
@_response = #<ActionDispatch::Response:0x0000000111df4438 @mon_data=#<Monitor:0x000000010795e680>, @mon_data_owner_object_id=36520, @header={"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"0", ...>
@_response_body = nil
@_routes = nil
@user = #<User:0x000000010641ea40 id: 1, name: "user1", created_at: Mon, 12 Jun 2023 00:36:48.844679000 UTC +00:00, updated_at: Mon, 12 Jun 2023 00:36:48.844679000 UTC +00:00, admin: false>
(rdbg:#debugger) b @user.hoge
#0  BP - Method  @user.hoge at /Users/kyntk/git/sample-app/app/models/user.rb:6
[1, 8] in ~/git/sample-app/app/models/user.rb
     1| class User < ApplicationRecord
     2|   validates :name, presence: true, uniqueness: true
     3|   has_many :articles, dependent: :destroy
     4|
     5|   def hoge
=>   6|     puts 'fuga'
     7|   end
     8| end
=>#0    User#hoge at ~/git/sample-app/app/models/user.rb:6
  #1    UsersController#show at ~/git/sample-app/app/controllers/users_controller.rb:15
  # and 58 frames (use `bt' command for all frames)

Stop by #0  BP - Method  @user.hoge at /Users/kyntk/git/sample-app/app/models/user.rb:6
(rdbg)
```

2回目に実行してもブレイクポイントが刺さらないということが置きました。

## 解決方法

- 1\. ブレイクポイントを設置する前に、ブレイクポイントを削除する
- 2\. `b User#hoge` のようにブレイクポイントを設置する

### 解説

2回目以降でブレイクポイントが刺さらなかった時に以下のようなメッセージが出力されていました。

```bash
duplicated breakpoint:  BP - Method  user.hoge at /Users/kyntk/git/sample-app/app/models/user.rb:6
```

ブレイクポイントを設置したいファイル、行数に対してはすでにブレイクポイントが設置されているようです。
しかし、同じ場所であっても、インスタンス `user` が異なるためブレイクポイントで処理が停止しないようです。

### 1. ブレイクポイントを設置する前に、ブレイクポイントを削除する

そのため、ブレイクポイントを設置する前に、前回のものを削除してあげると毎回刺さるようになりました。

```diff_ruby:users_controller.rb
  # GET /users/1
  def show
-    binding.b(do: 'i ;; b @user.hoge')
+    binding.b(do: 'del 0 ;; i ;; b @user.hoge')

    @user.hoge

    render json: @user
  end
```

今回は0番目のブレイクポイントしか削除していないですが、、`binding.b(do: "del ;; i ;; b @user.hoge")`のように`del`の引数を指定しないと、全てのブレイクポイントを削除することができます。

### 2. `b User#hoge` のようにブレイクポイントを設置する

ブレイクポイントは `@user.hoge` のような記法以外にも、行数を渡したり、`User#hoge` のように記述する方法もあります。

```md
* `b[reak] <line>`
  * Set breakpoint on `<line>` at the current frame's file.
* `b[reak] <file>:<line>` or `<file> <line>`
  * Set breakpoint on `<file>:<line>`.
* `b[reak] <class>#<name>`
   * Set breakpoint on the method `<class>#<name>`.
* `b[reak] <expr>.<name>`
   * Set breakpoint on the method `<expr>.<name>`.
```

これを用いることで、2回目以降のブレイクポイントの設置は同じく duplicated のメッセージが表示されるものの、ブレイクポイントで止まってくれるようになりました。

```diff_ruby:users_controller.rb
  # GET /users/1
  def show
-    binding.b(do: 'i ;; b @user.hoge')
+    binding.b(do: 'i ;; b User#hoge')

    @user.hoge

    render json: @user
  end
```