Ruby on rails 从生产irb调试到方法

Ruby on rails 从生产irb调试到方法,ruby-on-rails,ruby,debugging,irb,byebug,Ruby On Rails,Ruby,Debugging,Irb,Byebug,当我查找某个问题时,例如针对特定的ActiveRecord对象,我经常发现自己在生产系统上执行以下操作: # RAILS_ENV=production bundle exec irb(main)> article = Article.find(123) => #<Article id: 123, title: "Foobar"> irb(main)> article.do_something(3) NoMethodError: undefined method `

当我查找某个问题时,例如针对特定的ActiveRecord对象,我经常发现自己在生产系统上执行以下操作:

# RAILS_ENV=production bundle exec

irb(main)> article = Article.find(123)
=> #<Article id: 123, title: "Foobar">
irb(main)> article.do_something(3)
NoMethodError: undefined method `id' for nil:NilClass
[1] pry(main)> require 'byebug'
=> true
[2] pry(main)> user = User.find(2)
  User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
=> #<User id: 2, name="XXX XXX">
[3] pry(main)> user.full_name
NameError: undefined local variable or method address for #<User:0x0055b168663590>

[4] pry(main)> binding.pry; user.full_name

[68, 73] in /usr/src/app/app/models/user.rb
   68:   end
   69: 
   70:   def full_name
=> 71:     "#{address.firstname} #{address.last_name}"
   72:   end
   73: end
(byebug) 
#RAILS_ENV=生产包执行
irb(main)>article=article.find(123)
=> #
irb(主要)>文章。做点什么(3)
NoMethodError:未定义nil:NilClass的方法'id'
有时我无法复制,为什么行
文章.dou_something(3)
会抛出错误,所以我想在生产模式下直接在服务器上调试它

现在的问题是:如何使用对象/实例
文章
上的参数
3
进入方法
#dou something

当然,可以用这种方法设置一个断点,重新加载生产,让所有客户等待该断点,直到我完成调试。。。但这不是最好的主意

那么,有没有一种方法可以从正在运行的irb/pry会话调试到特定实例的方法中呢?(两者都可以)


在生产服务器中调试是一个可怕的想法。来自PHP世界,我们总是这样做,只有在幸运的情况下有一个数据库备份,事情才会变得异常轰动

相反,您可以做的是设置一个暂存服务器-这将是一个运行在完全相同的平台上、具有完全相同设置的服务器。您甚至可以将cron与
pg_backups
结合使用,每天镜像生产数据库,这样您就可以尝试新功能,甚至向协作者展示它们。如果它爆炸了,那就不是世界末日——也没有丢失最终用户数据的风险

<>但是你可能会认为你应该编写测试,而不是使用断点或日志。编写一个复制问题并指定所需行为的测试。然后,您可以使用代码,并从测试状态知道您所做的工作是否正常。

您可以使用pry调试器(通过ruby 1.9.3)或pry byebug(ruby>=2)

这两种方法都允许您设置断点,允许您在代码运行时以交互方式单步执行代码,检查变量值、方法返回值等


您将如何使用生产数据进行管理我不太确定,但这将允许您调试特定的方法。

您可以将生产上的代码更改为要签入的值
\dou something
方法并运行
irb
进行检查。因为我们不会重新启动生产服务器,所以不用担心您的更改。

在尝试了更多的谷歌搜索之后,我想我找到了一个适合我的解决方案

  • 登录rails控制台/irb/pry会话
  • 设置您的案例(例如,加载您的模型,需要依赖项…),以便您可以在一行中执行要调试的代码
  • require'byebug'
    (或
    require'debugger'
    用于较旧的ruby版本)
  • 现在有趣的部分是:在要调试的行前面放一条调试器语句,如下
    binding.pry;user.do_某事
    调试器;用户。做点什么
  • 现在您在调试器中。也许你必须用
    next
    跳到下一行(或者如果你启用了快捷方式,就跳到
    n
    )来进入你的方法
  • 以下是我们生产系统的完整示例:

    # RAILS_ENV=production bundle exec
    
    irb(main)> article = Article.find(123)
    => #<Article id: 123, title: "Foobar">
    irb(main)> article.do_something(3)
    NoMethodError: undefined method `id' for nil:NilClass
    
    [1] pry(main)> require 'byebug'
    => true
    [2] pry(main)> user = User.find(2)
      User Load (0.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
    => #<User id: 2, name="XXX XXX">
    [3] pry(main)> user.full_name
    NameError: undefined local variable or method address for #<User:0x0055b168663590>
    
    [4] pry(main)> binding.pry; user.full_name
    
    [68, 73] in /usr/src/app/app/models/user.rb
       68:   end
       69: 
       70:   def full_name
    => 71:     "#{address.firstname} #{address.last_name}"
       72:   end
       73: end
    (byebug) 
    
    [1]撬(主)>需要“byebug”
    =>正确
    [2] 撬(主)>user=user.find(2)
    用户加载(0.3ms)从“用户”中选择“用户”。“用户id”=2限制1
    => #
    [3] pry(主)>user.full_名称
    NameError:未定义的局部变量或方法地址#
    [4] pry(主)>binding.pry;user.full_名称
    [68,73]in/usr/src/app/app/models/user.rb
    68:完
    69: 
    70:def全名
    =>71:“{address.firstname}{address.last_name}”
    72:完
    73:完
    (byebug)
    
    正如我所写,有时您无法在测试或机器上重现错误,有时您必须在生产系统上进行调试。我知道这是个坏主意,但是没有选择余地,我不得不这么做。我们有测试、dev和staging env,但是当bug在生产环境中抛出时,如果您不能在这些环境中重现它,那么这些env就没有多大帮助。所以,在生产环境中调试是最后的选择,这正是我想要避免的。想象一下一个每秒调用数千次的方法,你在其中编写了一些
    put
    语句这就是调试的艺术,您不应该在使用
    put
    时不考虑
    put
    在这个地方,您认为它有问题。如果我听起来像个a-hole,很抱歉,但这里最可能的解释是您忘记在生产中运行迁移。如果您发现很难记住运行迁移(我们都这么做),您可以使用运行
    rake db:status
    的post-commit钩子作为提醒。该错误只是为了演示,不是真正的错误。问题是如何从irb/pry/rails控制台上下文使用调试器进入该方法非常聪明,喜欢!