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
attr_writerは書き込み用のprice=だけを定義します。読み出したい場合はattr_accessor(またはattr_reader)が必要です。
直し方: writer を accessor にします。
パターン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
「書けるプロパティなら読めるはず」という思い込みは誤りです。読み書きは別々のメソッドとして定義されます。
直し方: writer を accessor にします。
パターン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
読み書き両方が必要な場合は、最初からattr_accessorを使うのが簡潔です。
直し方: writer を accessor にします。
パターン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
attr_writerだけのクラスでは、初期化した値を後から読み出す手段がありません。
直し方: writer を accessor にします。
パターン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
attr_reader・attr_writer・attr_accessorの違いを、読み書きどちらが必要かで使い分ける必要があります。
直し方: writer を accessor にします。
よくある誤解
「attr_writerで宣言したプロパティなら、読み出しも自動でできるはず」という思い込みは誤りです。attr_writerは書き込み専用で、読み出し用メソッドを別に用意(attr_readerまたはattr_accessor)しない限りNoMethodErrorになります。
まとめ
attr_writer だけでは値を読み出せない(attr_accessor との違い)は中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。