Code Fix

中級

attr_writer だけでは値を読み出せない(attr_accessor との違い)

attr_writerは代入用のメソッド(name=)だけを定義し、読み出し用のメソッド(name)は定義しません。値を読み書き両方したい場合はattr_accessorを使う必要があります。

エラーメッセージの読み方

main.rb:10:in `<main>': undefined method `price' for an instance of Product (NoMethodError)
main.rb
ファイル名
10
行番号 — 実際にクラッシュした行
<main>
発生場所 — <main> ならトップレベル、メソッド名ならそのメソッドの中
NoMethodError
例外クラス — 何が起きたか。ここを検索するのが最短です
undefined method `price' for an instance of Product
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  class Product
 2    attr_writer   :price
               ^
 3  
 4    def initialize(price)
 5      self.price = price
 6    end
 7  end
 8  
 9  item = Product.new(1000)
10  puts item.price
main.rb:10:in `<main>': undefined method `price' for an instance of Product (NoMethodError)

attr_writerは書き込み用のprice=だけを定義します。読み出したい場合はattr_accessor(またはattr_reader)が必要です。

直し方: writeraccessor にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  class Ticket
 2    attr_writer   :seat
               ^
 3  
 4    def initialize(seat)
 5      self.seat = seat
 6    end
 7  end
 8  
 9  item = Ticket.new("12A")
10  puts item.seat
main.rb:10:in `<main>': undefined method `seat' for an instance of Ticket (NoMethodError)

「書けるプロパティなら読めるはず」という思い込みは誤りです。読み書きは別々のメソッドとして定義されます。

直し方: writeraccessor にします。

この問題を解いてみる →

パターン3

 1  class Card
 2    attr_writer   :number
               ^
 3  
 4    def initialize(number)
 5      self.number = number
 6    end
 7  end
 8  
 9  item = Card.new("4242")
10  puts item.number
main.rb:10:in `<main>': undefined method `number' for an instance of Card (NoMethodError)

読み書き両方が必要な場合は、最初からattr_accessorを使うのが簡潔です。

直し方: writeraccessor にします。

この問題を解いてみる →

パターン4

 1  class Profile
 2    attr_writer   :bio
               ^
 3  
 4    def initialize(bio)
 5      self.bio = bio
 6    end
 7  end
 8  
 9  item = Profile.new("hi")
10  puts item.bio
main.rb:10:in `<main>': undefined method `bio' for an instance of Profile (NoMethodError)

attr_writerだけのクラスでは、初期化した値を後から読み出す手段がありません。

直し方: writeraccessor にします。

この問題を解いてみる →

パターン5

 1  class Device
 2    attr_writer   :status
               ^
 3  
 4    def initialize(status)
 5      self.status = status
 6    end
 7  end
 8  
 9  item = Device.new("on")
10  puts item.status
main.rb:10:in `<main>': undefined method `status' for an instance of Device (NoMethodError)

attr_reader・attr_writer・attr_accessorの違いを、読み書きどちらが必要かで使い分ける必要があります。

直し方: writeraccessor にします。

この問題を解いてみる →

よくある誤解

「attr_writerで宣言したプロパティなら、読み出しも自動でできるはず」という思い込みは誤りです。attr_writerは書き込み専用で、読み出し用メソッドを別に用意(attr_readerまたはattr_accessor)しない限りNoMethodErrorになります。

まとめ

attr_writer だけでは値を読み出せない(attr_accessor との違い)は中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)