undefined method for nil の原因と直し方
nilが入った変数に対してメソッドを呼び出そうとしたときに出るエラーです。値を取得し損ねた変数(見つからなかった検索結果など)をそのまま使うと、必ずここで止まります。
エラーメッセージの読み方
main.rb:3:in `<main>': undefined method `upcase' for nil (NoMethodError)
main.rb- ファイル名
3- 行番号 — 実際にクラッシュした行
<main>- 発生場所 — <main> ならトップレベル、メソッド名ならそのメソッドの中
NoMethodError- 例外クラス — 何が起きたか。ここを検索するのが最短です
undefined method `upcase' for nil- 詳細メッセージ — どの値が問題だったか
このエラーが出る典型パターン
パターン1
1 users = ["taro", "hanako"] 2 found = users.find { |u| u == "jiro " } ^ 3 puts found.upcase
findは条件に一致する要素が無いとnilを返します。見つからなかった変数にメソッドを呼ぶとここで止まります。
直し方: jiro を hanako にします。
パターン2
1 scores = {math: "eighty", science: "ninety"} 2 english = scores[:english] ^ 3 puts english.upcase
ハッシュに存在しないキーでアクセスすると、エラーにならず静かにnilが返ります。
直し方: :english を :math にします。
パターン3
1 nums = [15.5, 42.2, 7.1] 2 big = nums.detect { |n| n > 100 } ^ 3 puts big.round
条件に合う要素が無いとdetectはnilを返します。しきい値が高すぎて何も見つからないと、後の行でエラーになります。
直し方: 100 を 10 にします。
パターン4
1 config = {timeout: 30} 2 retries = config[:retries] ^ 3 puts retries + 1
ハッシュに登録されていないキーの値はnilです。nilに対する+も未定義のメソッド呼び出しになります。
直し方: :retries を :timeout にします。
パターン5
1 inventory = {"apple" => 5, "banana" => 3} 2 count = inventory["orange"] ^ 3 puts count + 1
在庫に無い商品名で検索すればnilが返ります。存在確認をせずに計算に使うとエラーになります。
直し方: orange を apple にします。
よくある誤解
「変数に何か入っていればメソッドを呼べるはず」という思い込みは誤りです。nilは専用のクラスNilClassのオブジェクトで、upcaseのような文字列用メソッドは持っていません。
実務での勘所
Rubyの「あらゆるものはオブジェクトである」という哲学は、nilにも例外なく適用されています。nilはNilClassという専用のクラスの、れっきとしたオブジェクトであり、nil.class、nil.methods、nil.to_sのように、他のオブジェクトと同じ作法でメソッドを呼べます。ただしNilClassが持つメソッドはto_s、to_a、nil?など数個の限られたものだけで、upcaseのような文字列用メソッドは含まれていません。JavaやC#の「nullはオブジェクトではない特殊な無」という扱いとは違い、Rubyのエラーは通常のメソッド呼び出し失敗と同じ枠組みで説明されます。