LoginSignup
5
2

More than 3 years have passed since last update.

[Ruby][初心者向け] コンソールで例外が発生したときは、バックトレースを表示して原因を調べよう

Last updated at Posted at 2020-02-20

TL;DR

  • コンソール (irb や pry) で例外が発生しても、バックトレースが表示されないので原因がわからないことがある。
  • コンソールで例外時のバックトレースを表示するには
    • 特殊変数 $@ を参照する。
    • wtf コマンドを使う (pry 限定) 。
      • ちなみに、現実世界の会話では wtf (What the Fxck!) なんてあまり使わないように 🙅‍♀️

バージョン情報

$ ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin18]

$ bin/rails -v
Rails 6.0.1  

実例

以下のモデルを作成した。

app/models/hunter.rb
class Hunter < ApplicationRecord
  validates name, presence: true
end

早速 bin/rails c (irb) で動作を確認してみると謎のエラーが発生した。

irb(main):008:0> Hunter.create!(name: 'クラピカ')
Traceback (most recent call last):
        1: from (irb):8
NoMethodError (undefined method `Hunter' for #<Hunter:0x00007f8a322f52d8>)

Hunter#Hunter というメソッドがないって言われる……。なんだこの HUNTER×HUNTER みたいなへんちくりんなエラーは 🤔

それにしても、他に情報が何も出力されないのでエラーの原因がさっぱりわからない。こういうときはメソッドの呼び出し状況であるバックトレースを出力する。Ruby では $@ という特殊変数でバックトレースを参照することができる。

irb(main):002:0> puts $@
/Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
/Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate'
/Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each'
/Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate'
# 略
/Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.1/lib/active_record/persistence.rb:55:in `create!'
(irb):8:in `irb_binding'
# 略
-e:1:in `<main>'
=> nil

バックトレースに validate というキーワードがあったのでバリデーション周りを疑ってみる。すると本来シンボルであるはずの validates の引数がシンボルになっていなかったのが原因だと判明した!

app/models/hunter.rb
class Hunter < ApplicationRecord
  # name が self.name すなわち Hunter.name と解釈されて "Hunter" を返していた。
  # name を :name に修正した。
  validates :name, presence: true
end

しかしこの方法はちょっと不便だ。もう一度 $@ を参照しようとすると空になってしまう。

irb(main):002:0> puts $@
/Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
/Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate'
/Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each'
/Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate'
# 略
/Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activerecord-6.0.1/lib/active_record/persistence.rb:55:in `create!'
(irb):8:in `irb_binding'
# 略
-e:1:in `<main>'
=> nil
irb(main):003:0> puts $@

=> nil

そこで irb をより強力にしたツールである pry を使う。Gemfile に pry-rails を追加して bundle install しておく。

Gemfile
group :development, :test do
  gem 'pry-rails'
end

bin/rails c で動作を確認してみる。

[1] pry(main)> Hunter.create!(name: 'クラピカ')
NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088>
from /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'

wtf と入力すると、例外のバックトレースが表示される。すべてではなく先頭から数行が表示される。

[2] pry(main)> wtf
Exception: NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088>
--
0: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
1: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate'
2: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each'
3: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate'
4: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:429:in `block in make_lambda'

もう一度入力してもバックトレースが表示される。おもしろいことに wtf!wtf!!? のように wtf の後に !? をつけると、つけた量に比例して表示されるバックトレースの行数が増える。

[3] pry(main)> wtf!
Exception: NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088>
--
0: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
1: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate'
2: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each'
3: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate'
4: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:429:in `block in make_lambda'
5: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:201:in `block (2 levels) in halting'
6: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:607:in `block (2 levels) in default_terminator'
7: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:606:in `catch'
8: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:606:in `block in default_terminator'
9: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activesupport-6.0.1/lib/active_support/callbacks.rb:202:in `block in halting'

バックトレースを最後まで表示したい場合は wtf -v と入力する。

[4] pry(main)> wtf -v
Exception: NoMethodError: undefined method `Hunter' for #<Hunter:0x00007fe654afd088>
--
 0: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/attribute_methods.rb:431:in `method_missing'
 1: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:150:in `block in validate'
 2: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `each'
 3: /Users/killua/myapp/vendor/bundle/ruby/2.6.0/gems/activemodel-6.0.1/lib/active_model/validator.rb:149:in `validate'
# 略
73: /Users/killua/.rbenv/versions/2.6.5/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
74: /Users/killua/.rbenv/versions/2.6.5/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
75: -e:1:in `<main>'

参考

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2