I am having a hard time understanding attr_accessor in Ruby. Can someone explain this to me?

17 upvote
  flag
1 upvote
  flag
Does attr_accessor work this same way in Git? I'm finding that some tutorials don't explain enough and others assume prior knowledge. – Angelfirenze
7 upvote
  flag
@Angelfirenze, git has nothing to do with attr_accessor. Git is a version control software, whereas attr_accessor is a method in Ruby. – Uzbekjon

18 Answers 11

Basically they fake publicly accessible data attributes, which Ruby doesn't have.

4 upvote
  flag
Basically this answer is also correct !! – Driss Bounouar
3 upvote
  flag
Though this comment isn't entirely useful, it is true. Highlights the fact that public data attributes don't exist outside of "get" methods in Ruby, which is really useful info for someone trying to learn the language. – Eric Dand
1 upvote
  flag
This really shouldn't be downvoted. As a non-Ruby guy trying to figure this stuff out, this answer is very helpful! – Brad
1 upvote
  flag
Agreed, seems very simmilar to C#'s name {get; set;} – David Miler

attr_accessor is just a method. (The link should provide more insight with how it works - look at the pairs of methods generated, and a tutorial should show you how to use it.)

The trick is that class is not a definition in Ruby (it is "just a definition" in languages like C++ and Java), but it is an expression that evaluates. It is during this evaluation when the attr_accessor method is invoked which in turn modifies the current class - remember the implicit receiver: self.attr_accessor, where self is the "open" class object at this point.

The need for attr_accessor and friends, is, well:

  1. Ruby, like Smalltalk, does not allow instance variables to be accessed outside of methods1 for that object. That is, instance variables cannot be accessed in the x.y form as is common in say, Java or even Python. In Ruby y is always taken as a message to send (or "method to call"). Thus the attr_* methods create wrappers which proxy the instance @variable access through dynamically created methods.

  2. Boilerplate sucks

Hope this clarifies some of the little details. Happy coding.


1 This isn't strictly true and there are some "techniques" around this, but there is no syntax support for "public instance variable" access.

4 upvote
  flag
+1 for explaining the semantics! – bchurchill
upvote
  flag
When you say attr_accessor is "just a method" i get it. But what is the syntax used to call that method called? I'm having trouble finding the section in the ruby documentation that talks about syntax like some_method :name => "whatever", :notherName, :etc – B T

attr_accessor is very simple:

attr_accessor :foo

is a shortcut for:

def foo=(val)
  @foo = val
end

def foo
  @foo
end

it is nothing more than a getter/setter for an object

1 upvote
  flag
Calling it a 'shortcut' sounds like it's syntax sugar or some form of macro expanded by the interpreter (instead of the method that it actually is). – Phrogz
9 upvote
  flag
your answer is fine. 'Shortcut' means "a shorter alternative route" according to my dictionary, not "syntax sugar" or "macro interpreted by the interpreter". – bowsersenior

It is just a method that defines getter and setter methods for instance variables. An example implementation would be:

def self.attr_accessor(*names)
  names.each do |name|
    define_method(name) {instance_variable_get("@#{name}")} # This is the getter
    define_method("#{name}=") {|arg| instance_variable_set("@#{name}", arg)} # This is the setter
  end
end
upvote
  flag
handling multiple attributes in this way is great ! – Wasif Hossain

attr_accessor is (as @pst stated) just a method. What it does is create more methods for you.

So this code here:

class Foo
  attr_accessor :bar
end

is equivalent to this code:

class Foo
  def bar
    @bar
  end
  def bar=( new_value )
    @bar = new_value
  end
end

You can write this sort of method yourself in Ruby:

class Module
  def var( method_name )
    inst_variable_name = "@#{method_name}".to_sym
    define_method method_name do
      instance_variable_get inst_variable_name
    end
    define_method "#{method_name}=" do |new_value|
      instance_variable_set inst_variable_name, new_value
    end
  end
end

class Foo
  var :bar
end

f = Foo.new
p f.bar     #=> nil
f.bar = 42
p f.bar     #=> 42
upvote
  flag
Don't think this well help the OP much since in his "tons of Google searches" he most likely ran across the standard definitions of attr_accessor in the official ruby docs. – bowsersenior
10 upvote
  flag
@bowsersenior you might be right, but it sure helped me. – ellisbben
1 upvote
  flag
This is a great example of where metaprogramming is used in even the most beginner-level scenarios. Very nice. – John Simon
1 upvote
  flag
I was looking for an implementation sketch of attr_accessor and found here at last ! Though it solved my problem, but I am curious to know where(book/official doc) can I find an implementation example like this? – Wasif Hossain
up vote 1936 down vote accepted

Let's say you have a class Person.

class Person
end

person = Person.new
person.name # => no method error

Obviously we never defined method name. Let's do that.

class Person
  def name
    @name # simply returning an instance variable @name
  end
end

person = Person.new
person.name # => nil
person.name = "Dennis" # => no method error

Aha, we can read the name, but that doesn't mean we can assign the name. Those are two different methods. The former is called reader and latter is called writer. We didn't create the writer yet so let's do that.

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Dennis'
person.name # => "Dennis"

Awesome. Now we can write and read instance variable @name using reader and writer methods. Except, this is done so frequently, why waste time writing these methods every time? We can do it easier.

class Person
  attr_reader :name
  attr_writer :name
end

Even this can get repetitive. When you want both reader and writer just use accessor!

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Dennis"
person.name # => "Dennis"

Works the same way! And guess what: the instance variable @name in our person object will be set just like when we did it manually, so you can use it in other methods.

class Person
  attr_accessor :name

  def greeting
    "Hello #{@name}"
  end
end

person = Person.new
person.name = "Dennis"
person.greeting # => "Hello Dennis"

That's it. In order to understand how attr_reader, attr_writer, and attr_accessor methods actually generate methods for you, read other answers, books, ruby docs.

37 upvote
  flag
@hakunin - thank you for that clear answer. What is missing for me is why the Ruby syntax suggests a colon ':' for the instance variables in the attr_* statement? It seems that it would be more straight forward to use the same '@' syntax that is used elsewhere in the class to refer to the variable. – Will
173 upvote
  flag
@WilliamSmith To answer your question you need to understand that attr_accessor is a method called on the current class, and :name is a parameter you pass to that method. It's not a special syntax, it's a simple method call. If you were to give it @name variable, it wouldn't make sense, because @name would contain nil. So it would be like writing attr_accessor nil. You are not passing it a variable that it needs to create, you are passing the name that you want the variable to be called. – Max Chernyak aka hakunin
18 upvote
  flag
@hakunin - That makes total sense. I've just today been learning that ruby is actually 'running' as it parses through a file and that every statement and expression is actually a method call on some object. Including attr_accessor. Very helpful. – Will
upvote
  flag
I see now. So that's the equivalent of automatic properties in C#. Awesome! – Richard77
42 upvote
  flag
used Rails for 3 years, never even knew this. Shame – Sean Xiao
2 upvote
  flag
Getter and setter methods could not be told better. Cheers! – scaryguy
upvote
  flag
what if we use attr_reader , I guess still we can write to that attribute inside inilialize , for example attr_reader :name def initialize() @name = 'DDD' end – Buminda
4 upvote
  flag
@Buminda yes, but method name and variable @name are not the same thing. Don't confuse them. You have instance variable @name in your class, and you define attr_reader :name to be able to read it from the outside. Without attr_reader there is no simple way you can access @name outside of your class. – Max Chernyak aka hakunin
upvote
  flag
@hakunin Thank you so much for this , there couldn't be anything better than this – Haider Ali
upvote
  flag
Why not just give the object an instance variable and get and set it directly instead of using getter and setter methods? I don't see how this saves any time or work over accessing the variables directly. – jononomo
1 upvote
  flag
@JonCrowell there is (almost) no such thing as "getting/setting variables directly" from outside of the object. You can only do that inside the object. You can't do person.@name <- this doesn't exist. Ruby has special methods: person.instance_variable_get('@name') or person.instance_variable_set('@name') but you probably don't want to typically use them. – Max Chernyak aka hakunin
upvote
  flag
I'd like to group on the same line though.... attr_reader :a :b :c – mckenzm
upvote
  flag
i still dont get why there is colon, what does colon do here. i get it's being passed as a parameter but is it a symbol – Muhammad Umer
upvote
  flag
@hakunin Very neat explanation in simple language. I rarely find one these days.. thanks – whitehat
upvote
  flag
@MuhammadUmer I know this is dated but I figured I'd leave this for a future person wondering the same thing. its a colon because its a Symbol and this is is what Object#send expects to receive. While the call can take a String, it will have to convert said String to a Symbol. So by passing a Symbol you save a step. – engineerDave
upvote
  flag
One note missing from all comments so far is that since attr_reader, attr_writer and attr_accessor are all implemented in C, they are actually faster at run-time than writing the equivalent getters and setters manually in ruby. – MissingHandle
upvote
  flag
@MaxChernyakakahakunin - why is it neccessary to use the @ infront of name in your example above. The same without the @ works too in this case. but i notice some inconsistencies if i drop off the @ from the instance variable with an attr_accessor being set. thanks – OK999

Simply attr-accessor creates the getter and setter methods for the specified attributes

I think part of what confuses new Rubyists/programmers (like myself) is:

"Why can't I just tell the instance it has any given attribute (e.g., name) and give that attribute a value all in one swoop?"

A little more generalized, but this is how it clicked for me:

Given:

class Person
end

We haven't defined Person as something that can have a name or any other attributes for that matter.

So if we then:

baby = Person.new

...and try to give them a name...

baby.name = "Ruth"

We get an error because, in Rubyland, a Person class of object is not something that is associated with or capable of having a "name" ... yet!

BUT we can use any of the given methods (see previous answers) as a way to say, "An instance of a Person class (baby) can now have an attribute called 'name', therefore we not only have a syntactical way of getting and setting that name, but it makes sense for us to do so."

Again, hitting this question from a slightly different and more general angle, but I hope this helps the next instance of class Person who finds their way to this thread.

Simply put it will define a setter and getter for the class.

Note that

attr_reader :v is equivalant to 
def v
  @v
end

attr_writer :v is equivalant to
def v=(value)
  @v=value
end

So

attr_accessor :v which means 
attr_reader :v; attr_writer :v 

are equivalant to define a setter and getter for the class.

If you are familiar with OOP concept, You must familiar with getter and setter method. attr_accessor does the same in Ruby.

Getter and Setter in General Way

class Person
  def name
    @name
  end

  def name=(str)
    @name = str
  end
end

person = Person.new
person.name = 'Eshaan'
person.name # => "Eshaan"

Setter Method

def name=(val)
  @name = val
end

Getter method

def name
  @name
end

Getter and Setter method in Ruby

class Person
  attr_accessor :name
end

person = Person.new
person.name = "Eshaan"
person.name # => "Eshaan"
2 upvote
  flag
perfect explanation! It is a very handy behavior and can be overridden too very easily. – Rubyrider

Defines a named attribute for this module, where the name is symbol.id2name, creating an instance variable (@name) and a corresponding access method to read it. Also creates a method called name= to set the attribute.

module Mod
  attr_accessor(:one, :two)
end
Mod.instance_methods.sort   #=> [:one, :one=, :two, :two=]

I faced this problem as well and wrote a somewhat lengthy answer to this question. There are some great answers on this already, but anyone looking for more clarification, I hope my answer can help

Initialize Method

Initialize allows you to set data to an instance of an object upon creation of the instance rather than having to set them on a separate line in your code each time you create a new instance of the class.

class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end


  def greeting
    "Hello #{@name}"
  end
end

person = Person.new("Denis")
puts person.greeting

In the code above we are setting the name “Denis” using the initialize method by passing Dennis through the parameter in Initialize. If we wanted to set the name without the initialize method we could do so like this:

class Person
  attr_accessor :name

  # def initialize(name)
  #     @name = name
  # end

  def greeting
    "Hello #{name}"
  end
end

person = Person.new
person.name = "Dennis"
puts person.greeting

In the code above, we set the name by calling on the attr_accessor setter method using person.name, rather than setting the values upon initialization of the object.

Both “methods” of doing this work, but initialize saves us time and lines of code.

This is the only job of initialize. You cannot call on initialize as a method. To actually get the values of an instance object you need to use getters and setters (attr_reader (get), attr_writer(set), and attr_accessor(both)). See below for more detail on those.

Getters, Setters (attr_reader, attr_writer, attr_accessor)

Getters, attr_reader: The entire purpose of a getter is to return the value of a particular instance variable. Visit the sample code below for a breakdown on this.

class Item

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

  def item_name
    @item_name
  end

  def quantity
     @quantity
  end
end

example = Item.new("TV",2)
puts example.item_name
puts example.quantity

In the code above you are calling the methods “item_name” and “quantity” on the instance of Item “example”. The “puts example.item_name” and “example.quantity” will return (or “get”) the value for the parameters that were passed into the “example” and display them to the screen.

Luckily in Ruby there is an inherent method that allows us to write this code more succinctly; the attr_reader method. See the code below;

class Item

attr_reader :item_name, :quantity

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

end

item = Item.new("TV",2)
puts item.item_name
puts item.quantity

This syntax works exactly the same way, only it saves us six lines of code. Imagine if you had 5 more state attributable to the Item class? The code would get long quickly.

Setters, attr_writer: What crossed me up at first with setter methods is that in my eyes it seemed to perform an identical function to the initialize method. Below I explain the difference based on my understanding;

As stated before, the initialize method allows you to set the values for an instance of an object upon object creation.

But what if you wanted to set the values later, after the instance was created, or change them after they have been initialized? This would be a scenario where you would use a setter method. THAT IS THE DIFFERENCE. You don’t have to “set” a particular state when you are using the attr_writer method initially.

The code below is an example of using a setter method to declare the value item_name for this instance of the Item class. Notice that we continue to use the getter method attr_reader so that we can get the values and print them to the screen, just in case you want to test the code on your own.

class Item

attr_reader :item_name

  def item_name=(str)
    @item_name = (str)
  end

end

The code below is an example of using attr_writer to once again shorten our code and save us time.

class Item

attr_reader :item_name
attr_writer :item_name

end

item = Item.new
puts item.item_name = "TV"

The code below is a reiteration of the initialize example above of where we are using initialize to set the objects value of item_name upon creation.

class Item

attr_reader :item_name

  def initialize(item_name)
    @item_name = item_name
  end

end

item = Item.new("TV")
puts item.item_name

attr_accessor: Performs the functions of both attr_reader and attr_writer, saving you one more line of code.

Most of the above answers use code. There is no point me repeating what they say, so I'll try to explain the concept without code:

explanation

Outside parties cannot access internal CIA secrets

  • Let's imagine a really secret place. An agency. Let's call this agency the CIA. Nobody knows what's happening in the CIA apart from the people inside the CIA. In other words, external people cannot access any information in the CIA. But because it's no good having an organisation that is completely secret, certain information is made available to the outside world - only things that the CIA wants everyone to know about of course: e.g. the Director of the CIA, how environmentally friendly this department is compared to all other government departments etc. Other information: e.g. who are its covert operatives in Iraq or Afghanistan - these types of things will probably remain a secret for the next 150 years.

  • You can only access information which the CIA makes available to the public (if you're Joe Bloggs off the street). Or to use CIA parlance you can only access information that is "cleared".

    The information that the CIA wants to make available to the general public outside the CIA are called: attributes.

The meaning of read and write attributes:

  • In the case of the CIA, most attributes are "read only". This means you can ask: "who is the director of the CIA?" and you will get a straight answer. But what you cannot do with "read only" attributes is make changes changes in the CIA. e.g. you cannot making a phone call and suddenly decide that you want Kim Kardashian to be the Director, or that you want Paris Hilton to be the Commander in Chief. Imagine all CIA information is noted down on a piece of paper. Basically you cannot add/subtract/edit or write anything on that paper if you don't have "write" access. If read access was the only thing you had, well tough pities.

  • If the attributes gave you "write" access, then you could do that.

    In other words accessors allow you to make inquiries, or to make changes, to organisations that otherwise do not let external people in.

Objects inside a class can easily access each other

  • On the other hand, if you were already inside the CIA, then you could easily call up your CIA operative in Kabul and ask him if he wants to have a beer with the local Kabul informant after work. But if you're outside the CIA, you simply will not be given access: you will not be able to know who they are (read access), and you will not be able to change their mission (write access).

Exact same thing with classes and your ability to access variables, properties and methods within them.

I hope that helps!

upvote
  flag
Your explanation makes sense! +1 Sorry, are you sure that the expression "information which is cleared by the CIA is right? – kouty
upvote
  flag
there are various "clearance" levels in the CIA: e.g. Top Secret (nobody but the Prez),or public trust (everyone can read that info). The CIA actually provides a lot of very cool facts! – BKSpurgeon

The main functionality of attr_accessor over the other ones is the capability of accessing data from other files.
So you usually would have attr_reader or attr_writer but the good news is that Ruby lets you combine these two together with attr_accessor. I think of it as my to go method because it is more well rounded or versatile. Also, peep in mind that in Rails, this is eliminated because it does it for you in the back end. So in other words: you are better off using attr_acessor over the other two because you don't have to worry about being to specific, the accessor covers it all. I know this is more of a general explanation but it helped me as a beginner.

Hope this helped!

Attributes and accessor methods

Attributes are class components that can be accessed from outside the object. They are known as properties in many other programming languages. Their values are accessible by using the "dot notation", as in object_name.attribute_name. Unlike Python and a few other languages, Ruby does not allow instance variables to be accessed directly from outside the object.

class Car
  def initialize
    @wheels = 4  # This is an instance variable
  end
end

c = Car.new
c.wheels     # Output: NoMethodError: undefined method `wheels' for #<Car:0x00000000d43500>

In the above example, c is an instance (object) of the Car class. We tried unsuccessfully to read the value of the wheels instance variable from outside the object. What happened is that Ruby attempted to call a method named wheels within the c object, but no such method was defined. In short, object_name.attribute_name tries to call a method named attribute_name within the object. To access the value of the wheels variable from the outside, we need to implement an instance method by that name, which will return the value of that variable when called. That's called an accessor method. In the general programming context, the usual way to access an instance variable from outside the object is to implement accessor methods, also known as getter and setter methods. A getter allows the value of a variable defined within a class to be read from the outside and a setter allows it to be written from the outside.

In the following example, we have added getter and setter methods to the Car class to access the wheels variable from outside the object. This is not the "Ruby way" of defining getters and setters; it serves only to illustrate what getter and setter methods do.

class Car
  def wheels  # getter method
    @wheels
  end

  def wheels=(val)  # setter method
    @wheels = val
  end
end

f = Car.new
f.wheels = 4  # The setter method was invoked
f.wheels  # The getter method was invoked
# Output: => 4

The above example works and similar code is commonly used to create getter and setter methods in other languages. However, Ruby provides a simpler way to do this: three built-in methods called attr_reader, attr_writer and attr_acessor. The attr_reader method makes an instance variable readable from the outside, attr_writer makes it writeable, and attr_acessor makes it readable and writeable.

The above example can be rewritten like this.

class Car
  attr_accessor :wheels
end

f = Car.new
f.wheels = 4
f.wheels  # Output: => 4

In the above example, the wheels attribute will be readable and writable from outside the object. If instead of attr_accessor, we used attr_reader, it would be read-only. If we used attr_writer, it would be write-only. Those three methods are not getters and setters in themselves but, when called, they create getter and setter methods for us. They are methods that dynamically (programmatically) generate other methods; that's called metaprogramming.

The first (longer) example, which does not employ Ruby's built-in methods, should only be used when additional code is required in the getter and setter methods. For instance, a setter method may need to validate data or do some calculation before assigning a value to an instance variable.

It is possible to access (read and write) instance variables from outside the object, by using the instance_variable_get and instance_variable_set built-in methods. However, this is rarely justifiable and usually a bad idea, as bypassing encapsulation tends to wreak all sorts of havoc.

Another way to understand it is to figure out what error code it eliminates by having attr_accessor.

Example:

class BankAccount    
  def initialize( account_owner )
    @owner = account_owner
    @balance = 0
  end

  def deposit( amount )
    @balance = @balance + amount
  end

  def withdraw( amount )
    @balance = @balance - amount
  end
end

The following methods are available:

$ bankie = BankAccout.new("Iggy")
$ bankie 
$ bankie.deposit(100)
$ bankie.withdraw(5)

The following methods throws error:

$ bankie.owner     #undefined method `owner'... 
$ bankie.balance   #undefined method `balance'...

owner and balance are not, technically, a method, but an attribute. BankAccount class does not have def owner and def balance. If it does, then you can use the two commands below. But those two methods aren't there. However, you can access attributes as if you'd access a method via attr_accessor!! Hence the word attr_accessor. Attribute. Accessor. It accesses attributes like you would access a method.

Adding attr_accessor :balance, :owner allows you to read and write balance and owner "method". Now you can use the last 2 methods.

$ bankie.balance
$ bankie.owner

To summarize an attribute accessor aka attr_accessor gives you two free methods.

Like in Java they get called getters and setters.

Many answers have shown good examples so I'm just going to be brief.

#the_attribute

and

#the_attribute=

In the old ruby docs a hash tag # means a method. It could also include a class name prefix... MyClass#my_method

Hmmm. Lots of good answers. Here is my few cents on it.

  • attr_accessor is a simple method that helps us in cleaning(DRY-ing) up the repeating getter and setter methods.

  • So that we can focus more on writing business logic and not worry about the setters and getters.

Not the answer you're looking for? Browse other questions tagged or ask your own question.