如何为当前请求停止Rails调试器

时间:2011-05-31 09:37:55

标签: ruby-on-rails ruby ruby-on-rails-3 debugging ruby-debug

假设我的代码中有一个循环调用rails调试器几次

def show
    animals = ['dog', 'cat', 'owl', 'tiger']
    for animal in animals
    debugger
    # do something else
end

假设我使用--debugger选项启动了我的服务器,当查看此页面时,调试器将在每次循环运行时停止。

每次停止时我都可以输入cont,因此请求会继续,但这很乏味,特别是如果我们不是在谈论它在本例中出现4次,而是400次。 有没有办法让调试器继续运行而不会在循环的每个点停顿?

我目前的解决方法是重新启动服务器,但这很耗时。

9 个答案:

答案 0 :(得分:16)

只需在调试器语句上添加条件,使其仅在您需要时停止,例如:

debugger if animal == 'tiger'

或者,如果您想要仅在循环384上检查代码:

animals.each_with_index do |animal, i|
  debugger if i == 384
  # do something
end

或放入一个可以让你继续临时的变量:

continue_debugger = false
animals.each do |animal|
  debugger unless continue_debugger
  # in the debugger type `p continue_debugger = true` then `c` when done
end

答案 1 :(得分:12)

在迭代之前将debugger语句放在某处,然后在迭代中设置一个断点,稍后可以清除它。

示例:

def index

  debugger

  @things = Thing.all
  @things.each do |thing|
    # ... something you want to check out in the debugger
    thing.some_calculation
  end
end

进入调试器时,在内部设置断点:

b app/controllers/things_controller.rb:42

(其中42是你要打破的行号,如上面的thing.some_calculation。请注意,它必须是可执行的代码行 - 注释,空白行不起作用)。调试器将显示断点编号和位置:

Breakpoint 1 at .../app/controllers/things_controller.rb:42

现在,每次继续,你都会在断点处停下来。当您完成并想要完成请求时,请删除断点:

delete 1

再次继续,您将完成请求!

答案 2 :(得分:5)

看起来在ruby-debug的源代码中,对debugger的调用总是在命中时停止执行。因此,一个解决方案是按照Mori在他的“ad-hoc”解决方案中的建议做的,围绕调试器调用做一个条件,你可以调试调试器会话本身,这样你就可以避免调用debugger。这可能是最好的解决方案,除非你对所涉及的代码有一些强烈的唠叨纯度问题,否则我会做什么。

如果确实只想在没有外部条件的情况下在调试器会话本身内执行此操作,则 可能。你要做的是在代码本身设置一个断点,然后你可以在调试器中触发它时删除该断点:

require 'rubygems'
require 'ruby-debug'

Debugger.start
Debugger.add_breakpoint(__FILE__, __LINE__ + 2)
while true do
  puts "Hi"
  puts "mom"
end
Debugger.stop

这会产生这种互动:

Breakpoint 1 at debug_test.rb:10
debug_test.rb:10
puts "Hi"
(rdb:1) c
Hi
mom
Breakpoint 1 at debug_test.rb:10
debug_test.rb:10
puts "Hi"
(rdb:1) c
Hi
mom
Breakpoint 1 at debug_test.rb:10
debug_test.rb:10
puts "Hi"
(rdb:1) info b
Num Enb What
  1 y   at ./debug_test.rb:10
        breakpoint already hit 3 times
(rdb:1) del 1
(rdb:1) c
Hi
mom
Hi
mom
Hi
mom

......等等。

这样,您将在代码中设置断点,然后在完成后将其删除。请注意,无论何时调用行Debugger.add_breakpoint,它都会重新设置断点,这就是它在循环之外并指向2行的原因。这个技术很容易被提取到require - 一个只在加载你的服务器时设置断点的脚本 - 哎呀,你可以根据需要编写一个完整的框架类来控制Debugger模块。当然,如果你走得这么远,我会创建一个单例类来帮助你实现Mori的临时解决方案,并且不会或者不会调用调试器语句。

答案 3 :(得分:1)

我今天想出了另一个答案,我更喜欢这个:

debugger unless @no_debug

在每个有调试器停止的行上使用它。当你想停止停止时只需将@no_debug设置为某个东西。

答案 4 :(得分:0)

我对此问题有另一个答案:在要调试的类上设置@debug。这样你就可以做到:

  if (@debug && (the_condition)) then debugger end

  debugger unless !@debug 

然后当您完成调试器@debug = falsec时。

但是,我真的很高兴在实时代码中使用调试器“硬停止”。这些东西可能会被意外检查并被遗忘,直到出现故障。 @debug肯定也属于这个范围。为此,我认为我的理想解决方案将使用Matt's idea和一个脚本,该脚本在创建对象时在对象内部设置断点。这样你就可以得到你想要的调试,但你不会在源代码控制中有任何专门用于开发的代码。如果我找到这样的解决方案,我会更新这个答案。

答案 5 :(得分:0)

您始终可以从代码中注释掉debugger调用,然后在调试会话中键入reload。然后只需cont一次,请求将继续,而不会触发调试会话。

由于您处于开发模式,因此您可以稍后添加debugger回拨,它将正确触发。

答案 6 :(得分:0)

将此作为替代方案,因为此问题首先出现在我自己的搜索中。让我们假设您有一段代码在特定情况下无法正常工作,但在其他情况下工作,并且您有一大堆测试可以执行此操作,但一项特定测试失败。 PITA必须不断地在调试控制台中输入continue,直到你真正想要调试的测试为止,所以我开始使用这个约定:

在您的代码中:

def some_common_function
  debugger if defined? ::ASDF
  # do something
end

然后在你的测试中:

should "do this thing that it isn't doing under a specific circumstance" do
  # setup the specific situation
  ::ASDF = true
  # your tests
end

答案 7 :(得分:0)

如果我想要控制权,我就是

eval return

我将退出当前正在运行的函数,这通常会让我回到IRB [rails console]提示符。

答案 8 :(得分:0)

退出调试器,使用

  

全部退出

代替

  

继续

尽管这样做会产生一个错误,您可能必须删除调试器并再次发送请求,但这会使您摆脱所有循环