Lesson Wednesday

Reader and writer methods are so common in Ruby (and in programming in general) that Ruby has convenience methods for them. These attr methods make it easy to add read/write methods to our classes. They also make our code more readable.

Imagine that our Cat class has four attributes and we’d like to have read and write methods for all four of these attributes. Here’s the code:

class Cat
  def initialize(name, age, breed, address)
    @name = name
    @age = age
    @breed = breed
    @address = address
  end

  def name
    @name
  end

  def name=(name)
    @name = name
  end

  def age
    @age
  end

  def age=(age)
    @age = age
  end

  def breed
    @breed
  end

  def address=(address)
    @address = address
  end
end

That is a lot of code! To make matters worse, it’s difficult to tell which attributes have reader methods, which have writer methods, and which have both. In fact, one of the attributes in the code above doesn’t have a writer method, and another doesn't have a reader method. If you take a look for yourself, you can see why it’s a hassle to read this code.

We can simplify this code with Ruby’s attr methods. (attr is short for attribute.) There are three attr methods:

  • attr_reader: This adds a read method for an attribute.
  • attr_writer: This adds a write method for an attribute.
  • attr_accessor: This adds both a read and write method for an attribute.

Let’s use these attr methods in our Cat class:

class Cat
  attr_reader(:name, :breed)
  attr_writer(:address)
  attr_accessor(:age)

  def initialize(name, age, breed, address)
    @name = name
    @age = age
    @breed = breed
    @address = address
  end
end

attr methods take symbols as arguments and then create methods with those names. Any attributes passed into attr_reader will have a read method while any attributes passed into attr_writer will have a write method. Attributes passed into attr_accessor will have both a read and write method.

Not only is this code much shorter, but it’s also much more readable. We can quickly see the developer’s intent; name and breed are attributes that we should be able to read but we can’t overwrite them. We can write the address attribute but not read it — perhaps our cats would prefer to keep their current location secret. And we can both read and write a cat’s age attribute.

These methods are a great example of the Ruby philosophy of "convention over configuration." By using naming conventions, we can minimize configuration. These conventions save us time, energy and potential confusion down the road for anyone reading our code.

While attr methods are easy to set up, we still need to test them. It’s also important to consider exactly which methods each attribute will need. It’s easy to stick all of our attributes in an attr_accessor but that could potentially make our application less secure. It also makes our coding intentions more difficult to read and decipher.

Terminology


  • Attr method: A method to interact with an object's attribute.

  • attr_reader: This adds a read method for an attribute.

  • attr_writer: This adds a write method for an attribute.

  • attr_accessor: This adds both a read and write method for an attribute.

Example


class Cat
  attr_reader(:name, :breed)
  attr_writer(:address)
  attr_accessor(:age)

Use symbols (such as :name) to denote the attribute that should have the attr method.

Lesson 16 of 22
Last updated August 7, 2022