Ruby Classes and Objects — class initialize attr_accessor and self Explained
In this tutorial, you will learn about Ruby Classes and Objects. We cover key concepts, practical examples, and best practices to help you master this topic.
Ruby classes define objects with state and behavior using initialize constructors, attr_accessor for automatic getter/setter creation, and self for distinguishing instance-level from class-level context.
What You'll Learn
- Defining classes and creating objects
- Initialize method and constructor patterns
- attr_reader, attr_writer, and attr_accessor
- Instance methods vs class methods
- Self keyword and its various meanings
Why It Matters
Object-oriented programming is central to Ruby. Rails models are classes, controllers are classes, and even configuration objects are classes. Durga Antivirus Pro models threats, scans, and reports as Ruby classes. Doda Browser uses classes for tabs, bookmarks, and history entries. Understanding classes means understanding Ruby itself.
Real-World Use
A Rails application might have User, Post, and Comment classes with validations, associations, and custom methods. A Sinatra API uses classes for route handlers. A data processing tool uses classes for transformers, filters, and exporters.
flowchart LR
A["Classes & Objects"] --> B["Class Definition"]
B --> C["Initialize"]
C --> D["Attributes"]
D --> E["Methods"]
E --> F["Inheritance"]
A:::current --> B
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
style E fill:#dbeafe,stroke:#2563eb,color:#1e40af
style F fill:#f1f5f9,stroke:#94a3b8,color:#64748b
Defining a Class
class Person
end
alice = Person.new
puts alice.class # Person
The Initialize Method
The initialize method runs when you call new:
class Person
def initialize(name, age)
@name = name
@age = age
end
end
alice = Person.new("Alice", 25)
@name and @age are instance variables — they belong to the specific object.
Attribute Accessors
Instance variables are private by default. Use accessors to expose them:
attr_reader (Read Only)
class Person
attr_reader :name, :age
def initialize(name, age)
@name = name
@age = age
end
end
alice = Person.new("Alice", 25)
puts alice.name # "Alice"
puts alice.age # 25
# alice.name = "Bob" # NoMethodError (no writer)
attr_writer (Write Only)
class Person
attr_writer :name
def initialize(name)
@name = name
end
end
alice = Person.new("Alice")
alice.name = "Bob" # Works
# puts alice.name # NoMethodError (no reader)
attr_accessor (Read and Write)
class Person
attr_accessor :name, :age
def initialize(name, age)
@name = name
@age = age
end
end
alice = Person.new("Alice", 25)
puts alice.name # "Alice"
alice.name = "Bob"
puts alice.name # "Bob"
Instance Methods
class Calculator
def add(a, b)
a + b
end
def multiply(a, b)
a * b
end
def power(base, exp)
base ** exp
end
end
calc = Calculator.new
puts calc.add(5, 3) # 8
puts calc.multiply(4, 3) # 12
puts calc.power(2, 10) # 1024
Methods That Use Instance Variables
class BankAccount
attr_reader :balance
def initialize(initial_balance = 0)
@balance = initial_balance
end
def deposit(amount)
@balance += amount
puts "Deposited #{amount}. New balance: #{@balance}"
end
def withdraw(amount)
if amount > @balance
puts "Insufficient funds"
else
@balance -= amount
puts "Withdrew #{amount}. New balance: #{@balance}"
end
end
end
account = BankAccount.new(100)
account.deposit(50) # Deposited 50. New balance: 150
account.withdraw(30) # Withdrew 30. New balance: 120
account.withdraw(200) # Insufficient funds
Class Methods
Methods called on the class itself, not on instances:
class MathHelper
def self.pi
3.14159
end
def self.square(n)
n * n
end
end
puts MathHelper.pi # 3.14159
puts MathHelper.square(5) # 25
Alternative Syntax for Class Methods
class MathHelper
class << self
def pi
3.14159
end
def square(n)
n * n
end
end
end
The Self Keyword
self refers to the current object context:
class Person
attr_accessor :name
def initialize(name)
@name = name
end
def introduce
"Hi, I'm #{self.name}"
end
def rename(new_name)
self.name = new_name # Required for writer methods
end
end
alice = Person.new("Alice")
puts alice.introduce # Hi, I'm Alice
alice.rename("Bob")
puts alice.introduce # Hi, I'm Bob
In class methods, self is the class itself:
class Person
def self.species
"Homo sapiens"
end
def self.describe
"I am a #{self.species}"
end
end
puts Person.species # Homo sapiens
puts Person.describe # I am a Homo sapiens
Constructor Overloading
Ruby doesn't support multiple initialize methods. Use default values or class methods:
class User
attr_reader :name, :email, :role
def initialize(name, email, role: "user")
@name = name
@email = email
@role = role
end
def self.create_admin(name, email)
new(name, email, role: "admin")
end
def to_s
"#{@name} (#{@role})"
end
end
user = User.new("Alice", "alice@example.com")
admin = User.create_admin("Bob", "bob@example.com")
puts user # Alice (user)
puts admin # Bob (admin)
Object Equality
Ruby has several equality methods:
a = "hello"
b = "hello"
puts a == b # true — value equality
puts a.equal?(b) # false — same object? (identity)
puts a.eql?(b) # true — value and type equality
puts a.object_id # Some number
puts b.object_id # Different number
Common Mistakes
1. Forgetting attr_reader / attr_accessor
class Person
def initialize(name)
@name = name
end
end
p = Person.new("Alice")
puts p.name # NoMethodError (no reader defined)
2. Using @name When You Have attr_accessor
class Person
attr_accessor :name
def uppercase_name
@name.upcase # Works but bypasses the accessor
# Better: self.name.upcase
end
end
3. Forgetting self in Setter Methods
class Person
attr_accessor :name
def change_name(name)
name = name # This creates a local variable, doesn't call the setter!
# Correct: self.name = name
end
end
4. Confusing Class Methods and Instance Methods
class Calculator
def self.add(a, b)
a + b
end
def subtract(a, b)
a - b
end
end
Calculator.add(1, 2) # 3 (class method)
Calculator.subtract(1, 2) # NoMethodError (instance method)
calc = Calculator.new
calc.subtract(1, 2) # -1 (instance method)
calc.add(1, 2) # NoMethodError (class method on instance)
5. Not Using attr_reader for Read-Only Attributes
class Person
attr_accessor :ssn # Allows writing too
# Should be:
attr_reader :ssn
def initialize(ssn)
@ssn = ssn
end
end
Practice Questions
1. What does attr_accessor do?
It creates both getter and setter methods for the specified instance variables. attr_accessor :name creates name and name= methods.
2. What's the difference between @name and self.name?
@name directly accesses the instance variable. self.name calls the getter method. Use @name for direct access and self.name= (required) for setters.
3. How do you define a class method?
Use def self.method_name inside the class, or define inside class << self. Class methods are called on the class itself, not on instances.
4. What does the initialize method do?
It's the constructor — called automatically when Class.new is invoked. It sets up initial state for new objects.
Challenge: Create a Library class that maintains a collection of books with methods to add, remove, search by title, and display all books.
Solution
class Library
attr_reader :name
def initialize(name)
@name = name
@books = []
end
def add_book(title, author)
@books << { title: title, author: author }
end
def remove_book(title)
@books.reject! { |book| book[:title] == title }
end
def search(title)
@books.select { |book| book[:title].downcase.include?(title.downcase) }
end
def display
puts "#{@name}: #{@books.size} books"
@books.each { |b| puts " - #{b[:title]} by #{b[:author]}" }
end
end
lib = Library.new("City Library")
lib.add_book("1984", "George Orwell")
lib.add_book("Brave New World", "Aldous Huxley")
lib.add_book("Fahrenheit 451", "Ray Bradbury")
lib.display
puts "Search: #{lib.search("world").inspect}"
lib.remove_book("1984")
lib.display
Expected output:
City Library: 3 books
- 1984 by George Orwell
- Brave New World by Aldous Huxley
- Fahrenheit 451 by Ray Bradbury
Search: [{:title=>"Brave New World", :author=>"Aldous Huxley"}]
City Library: 2 books
- Brave New World by Aldous Huxley
- Fahrenheit 451 by Ray Bradbury
FAQ
{{< faq question="Can a class have multiple initialize methods?" >}}
No. Ruby classes can have only one initialize method. Use default parameter values or class Factory methods (like create_admin) to handle different construction scenarios.
{{< /faq >}}
{{< faq question="What's the difference between @@var and @var?" >}}
@@var is a class variable shared across the class hierarchy (including instances). @var in a class body is a class-level instance variable, while @var in an instance method is an instance variable.
{{< /faq >}}
{{< faq question="How do I make a method private?" >}}
Use the private keyword before the method definition. Private methods can only be called without an explicit receiver. Use protected for methods callable by instances of the same class.
{{< /faq >}}
{{< faq question="Can I reopen a class to add methods?" >}} Yes. Ruby supports open classes. You can add methods to existing classes, including built-in ones. This is called monkey patching. Use it carefully — it can cause conflicts. {{< /faq >}}
{{< faq question="What is the difference between new and initialize?" >}}
new is a class method that creates the object and then calls initialize on it. You can override new (as a class method) but rarely do. initialize is the instance method where you set up initial state.
{{< /faq >}}
Try It Yourself
# classes_demo.rb
class Counter
attr_reader :count
def initialize(start = 0)
@count = start
end
def increment
@count += 1
end
def decrement
@count -= 1
end
def reset
@count = 0
end
end
c = Counter.new(10)
puts "Start: #{c.count}"
puts "Increment: #{c.increment}"
puts "Increment: #{c.increment}"
puts "Decrement: #{c.decrement}"
c.reset
puts "Reset: #{c.count}"
Expected output:
Start: 10
Increment: 11
Increment: 12
Decrement: 11
Reset: 0
What's Next
Now that you understand classes, explore modules for organizing reusable code across classes.
| Topic | Description | Link |
|---|---|---|
| Ruby Modules | module, include, extend, prepend | {{< ref "10-modules" >}} |
| Ruby Inheritance | Superclass, < operator, ancestors | {{< ref "11-inheritance" >}} |
| Python Classes | Compare Python class patterns | Python |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro