Attr Accessor in Ruby

Nurudeen Ibrahim Apr 01, 2022
  1. Create an Instance Variable full_name Using a Simple Class in Ruby
  2. Use the attr_reader to Read Multiple Instance Variables in Ruby
  3. Use the attr_writer to Write Multiple Instance Variables in Ruby
  4. Combine Both attr_reader and attr_writer Into attr_accessor in Ruby
Attr Accessor in Ruby

The attr_accessor is a shortcut in Ruby OOP design for attr_reader and attr_writer.

Therefore, to understand attr_accessor, you must first understand how attr_reader and attr_writer work. To illustrate how these work, we will create a simple class.

Create an Instance Variable full_name Using a Simple Class in Ruby

class Employee
  def initialize(last_name, first_name)
    @full_name = "#{last_name} #{first_name}"
  end
end

employee1 = Employee.new('John', 'Doe')
puts employee1.full_name

Output:

undefined method 'full_name' for #<Employee:0x0000558c7cbc9400 @full_name="John Doe"> (NoMethodError)

The simple Employee class above has a constructor that accepts the employee’s last and first name and uses this to create an instance variable full_name.

If we create an instance of this class and read the full_name, we get a NoMethodError error, as shown in the output above. We will need to create another method that returns the instance variable.

class Employee
  def initialize(last_name, first_name)
    @full_name = "#{last_name} #{first_name}"
  end

  attr_reader :full_name
end

employee1 = Employee.new('John', 'Doe')
puts employee1.full_name

Output:

John Doe

Use the attr_reader to Read Multiple Instance Variables in Ruby

Does it mean if we have multiple instance variables that need to be read, we will have to create a method for each of them?

That would make our class unnecessarily long. As a result, Ruby provides us with attr_reader to achieve this.

class Employee
  attr_reader :full_name

  def initialize(last_name, first_name)
    @full_name = "#{last_name} #{first_name}"
  end
end

employee1 = Employee.new('John', 'Doe')
puts employee1.full_name

Output:

John Doe

As you can see in the code above, we have the same output as the previous code. The addition of attr_reader :full_name adds the full_name method under the hood, allowing us to write a concise class.

Let’s assume that we also need to reset the instance variable. We might try something like this:

class Employee
  attr_reader :full_name

  def initialize(last_name, first_name)
    @full_name = "#{last_name} #{first_name}"
  end
end

employee1 = Employee.new('John', 'Doe')
# After doing some operation on employee1 and we need
# to rename the full name
employee1.full_name = 'Nicolas Daniel'

Output:

undefined method 'full_name=' for #<Employee:0x000055bc12240940 @full_name="John Doe"> (NoMethodError)

One way to do that is to define a full_name= setter method that resets the instance variable.

class Employee
  attr_accessor :full_name

  def initialize(last_name, first_name)
    @full_name = "#{last_name} #{first_name}"
  end
end

employee1 = Employee.new('John', 'Doe')
# After doing some operation on employee1 and we need
# to rename the full name
employee1.full_name = 'Nicolas Daniel'
puts employee1.full_name

Output:

Nicolas Daniel

Use the attr_writer to Write Multiple Instance Variables in Ruby

Instead of defining a separate setter method as we have done here, Ruby also provides us with the attr_writer that can help us.

class Employee
  attr_accessor :full_name

  def initialize(last_name, first_name)
    @full_name = "#{last_name} #{first_name}"
  end
end

employee1 = Employee.new('John', 'Doe')
# After doing some operation on employee1 and we need
# to rename the full name
employee1.full_name = 'Nicolas Daniel'
puts employee1.full_name

Output:

Nicolas Daniel

As we can see in the output above, we have the same result with the addition of attr_writer, even though we have removed the setter method previously defined.

Combine Both attr_reader and attr_writer Into attr_accessor in Ruby

Our final code is a lot better than defining getter and setter methods for every of our instance variables, but Ruby still allows us to move a step further by combining both attr_reader and attr_writer into attr_accessor.

class Employee
  attr_accessor :full_name

  def initialize(last_name, first_name)
    @full_name = "#{last_name} #{first_name}"
  end
end

employee1 = Employee.new('John', 'Doe')
# After doing some operation on employee1 and we need
# to rename the full name
employee1.full_name = 'Nicolas Daniel'
puts employee1.full_name

Output:

Nicolas Daniel

As we can see above, with attr_accessor, we automatically have a getter and a setter for an instance variable.

Related Article - Ruby Variable