Attributes (attr_accessor)
Ruby is a dynamic, beginner-friendly programming language, and attributes are how an object exposes its data — attr_accessor generates the getter and setter methods so you don't write them by hand.
Learn Attributes (attr_accessor) in our free Ruby course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Ruby course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
By the end of this lesson you'll understand getters and setters, use attr_reader/writer/accessor, and write custom accessors with validation.
What You'll Learn in This Lesson
1️⃣ The Manual Way: Getters and Setters
Instance variables are private to the object. To expose one, you write a getter (a method that returns it) and a setter (a method named with a trailing = that assigns it). Seeing this by hand makes the shortcut obvious.
2️⃣ attr_accessor, attr_reader, attr_writer
attr_accessor :name generates both the getter and the setter automatically. Use attr_reader for read-only data (a getter only) and attr_writer for write-only. You list the attributes as symbols.
Your turn. Add the right accessors to a Product class so its name is editable but its SKU is read-only. Complete the TODO s, then run it.
Mini-Challenge: A Guarded Setter
Write a custom temperature= setter that validates its input — the real payoff of writing accessors yourself. Run with ruby thermostat.rb .
Common Errors (and the fix)
- "undefined method 'name='" — You used attr_reader (read-only) but tried to assign. Use attr_accessor .
- Passing strings instead of symbols — It's attr_accessor :name , with a leading colon.
- Setter not firing inside the class — Inside a method, write self.name = x ; a bare name = x creates a local variable.
- Forgetting to set @ in initialize — Accessors expose @name ; you still must assign it somewhere (usually initialize ).
- Custom setter shadowed by attr_accessor — Don't declare the same attribute in attr_accessor if you hand-write its setter; use attr_reader plus your setter.
Pro Tips
- 💡 Least access first: default to attr_reader ; only add a setter when callers truly need to change the value.
- 💡 Validate in setters: a custom value= is the perfect place to reject bad input.
- 💡 Group declarations: keep your attr_* lines at the top of the class for readability.
📋 Quick Reference — Attributes
Concept
Ruby Syntax
Read + write
attr_accessor :name
Read only
attr_reader :id
Write only
attr_writer :pw
Custom getter
def name; @name; end
Custom setter
def name=(v)
Set inside class
self.name = v
Frequently Asked Questions
🎉 Lesson Complete!
- ✅ Instance variables are private; getters/setters expose them
- ✅ attr_accessor generates both for you
- ✅ attr_reader = read-only; attr_writer = write-only
- ✅ Setters are methods named with a trailing =
- ✅ Hand-write accessors when you need validation or computation
- ✅ Next lesson: Modules & Mixins — share behaviour across classes
Practice quiz
What does attr_accessor :name generate?
- Only a getter named name
- Only a setter named name=
- Both a getter (name) and a setter (name=)
- An instance variable named name
Answer: Both a getter (name) and a setter (name=). attr_accessor writes both the getter and the setter for you at class-definition time.
Which macro creates a READ-ONLY attribute (getter only)?
- attr_reader
- attr_writer
- attr_accessor
- attr_const
Answer: attr_reader. attr_reader generates just the getter, so the value can be read but not written from outside.
If a class uses attr_reader :id, what happens when you call obj.id = 5?
- It silently does nothing
- It sets @id to 5
- It creates a new attribute
- It raises NoMethodError because no setter exists
Answer: It raises NoMethodError because no setter exists. attr_reader makes no setter, so assigning raises NoMethodError (undefined method 'id=').
How is a setter method named in Ruby?
- set_name
- name= (with a trailing equals sign)
- name!
- @name
Answer: name= (with a trailing equals sign). Ruby routes obj.name = x to the method name=(x); the trailing = is what makes it a setter.
You must pass attributes to attr_accessor as:
- Symbols, like :name
- Strings, like "name"
- Instance variables, like @name
- Local variables
Answer: Symbols, like :name. Accessor macros take symbols: attr_accessor :name, :age.
Inside an instance method, how do you correctly call the generated setter for name?
- name = x
- @name = x only
- self.name = x
- set name x
Answer: self.name = x. A bare name = x makes a local variable; self.name = x routes through the setter method.
attr_writer :password generates which method(s)?
- A getter only
- A setter only (write-only)
- Both getter and setter
- Neither
Answer: A setter only (write-only). attr_writer makes only the setter, useful for write-only values you don't want to expose.
Why would you hand-write a setter instead of using attr_accessor?
- It runs faster
- attr_accessor is deprecated
- Hand-written setters are required by Ruby
- To add validation or side effects when the value is set
Answer: To add validation or side effects when the value is set. A custom value= setter lets you validate or transform input — the payoff of writing it yourself.
Instance variables (the @-prefixed ones) are, by default:
- Public and readable from anywhere
- Private to the object — exposed only through methods
- Shared across all instances
- Automatically frozen
Answer: Private to the object — exposed only through methods. Instance variables are private; getters and setters are how you expose them to the outside.
Best practice for choosing accessors is usually to:
- Always use attr_accessor
- Never use accessor macros
- Start with the least access (e.g. attr_reader) and widen only when needed
- Use attr_writer for everything
Answer: Start with the least access (e.g. attr_reader) and widen only when needed. Default to read-only and add a setter only when callers truly need to change the value.
Continue this course
- Previous: Classes & Objects
- Next: Modules & Mixins