50

In testing a getter/setter pair in a rails model, I've found a good example of behavior I've always thought was odd and inconsistent.

In this example I'm dealing with class Folder < ActiveRecord::Base.

Folder belongs_to :parent, :class_name => 'Folder'

On the getter method, if I use:

def parent_name
  parent.name
end

...or...

def parent_name
  self.parent.name
end

...the result is exactly the same, I get the name of the parent folder. However, in the getter method if I use...

def parent_name=(name)
  parent = self.class.find_by_name(name)
end

... parent becomes nil, but if I use...

def parent_name=(name)
  self.parent = self.class.find_by_name(name)
end

...then then it works.

So, my question is, why do you need to declare self.method sometimes and why can you just use a local variable?

It seems the need for / use of self in ActiveRecord is inconsistent, and I'd like to understand this better so I don't feel like I'm always guessing whether I need to declare self or not. When should you / should you not use self in ActiveRecord models?

Andrew
  • 42,517
  • 51
  • 181
  • 281
  • 3
    Duplicate of [Why do ruby setters need `self.` qualification within the class?](http://StackOverflow.Com/q/44715/), [Calling attribute accessor methods from within the class](http://StackOverflow.Com/q/576428/), [When to use `self` in Ruby](http://StackOverflow.Com/q/1252031/), [local methods act differently when called with/without `self`. Why?](http://StackOverflow.Com/q/1296473/), [In Ruby, when should you use `self.` in your classes?](http://StackOverflow.Com/q/5068304/), [In Ruby, if we define a method called `c=`, why can't it be invoked by `c = 3`?](http://StackOverflow.Com/q/5111350/). – Jörg W Mittag Mar 03 '11 at 17:08
  • Also duplicated [here](http://stackoverflow.com/questions/6669527/use-of-ruby-self-keyword/6671310#6671310), wherein 'I was the learner, now I am the master' ;) – Andrew Jan 17 '15 at 02:11

1 Answers1

89

This is because attributes/associations are actually methods(getters/setters) and not local variables. When you state "parent = value" Ruby assumes you want to assign the value to the local variable parent.

Somewhere up the stack there's a setter method "def parent=" and to call that you must use "self.parent = " to tell ruby that you actually want to call a setter and not just set a local variable.

When it comes to getters Ruby looks to see if there's a local variable first and if can't find it then it tries to find a method with the same name which is why your getter method works without "self".

In other words it's not the fault of Rails, but it's how Ruby works inherently.

starball
  • 20,030
  • 7
  • 43
  • 238
pinkmexican
  • 930
  • 7
  • 4
  • 5
    Wow, perfect. It works as a getter because ruby doesn't find the local and so looks for a method instead. So, in other words, if I mean self I should use self, rather than leave it off. Wow, this was a very, very very helpful explanation. – Andrew Mar 03 '11 at 17:11
  • Indeed, thanks for the explanation (and for the well-written question). – Fábio Batista Mar 03 '11 at 21:05
  • [This answer's](http://stackoverflow.com/a/10127425/34386) explanation about the dynamic nature of ActiveRecord models' methods makes this even clearer. Ruby understands the class hierarchy but not necessarily those methods that are dynamically generated or handled via method_missing. – jxpx777 Oct 07 '13 at 12:48
  • Excellent explanation! Saved my life. Even though still feel a little bit more confusing right now, but I think I have grasped something really important concept here in my hand, as a slow learner, I trust I can understand the total of your explanation soon, thanks for this brilliant explanation again! – Jesse JunJing May 13 '21 at 04:13