Regarding the keyword self
in Rails, I know that the keyword refers to an instance of the class itself. For example, in self.encrypted_password
.
I have less of an idea why the attribute password
, passed as an parameter on the right hand side, isn't prefixed with the self
keyword too?
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
private
def encrypt_password
self.encrypted_password = encrypt(password)
end
def encrypt(string)
string # Only a temporary implementation!
end
end
Can someone explain when to use, or not use, the self
keyword?
Answer
The answer is simple: scope visibility.
def encrypt_password
self.encrypted_password = encrypt(password)
end
There is (or, rather, there should be at runtime) something called password
. In your case, it's an attribute from the database. But it also can be a local variable. If such name isn't found, error will be raised.
But you have to prefix encrypted_password
with self
to explicitly state that you're going to update instance attribute. Otherwise, new local variable encrypted_password
will be created. Obviously, not the effect you wanted.
More explanation
Here's a little snippet of code
class Foo
attr_accessor :var
def bar1
var = 4
puts var
puts self.var
end
end
f = Foo.new
f.var = 3
f.bar1
Output
4
3
So, as we can see, var
is assigned without self
keyword and, because of this, now there are two names var
in the scope: local variable and instance attribute. Instance attribute is hidden by local variable, so if you really want to access it, use self
.
The question has nothing to do with Rails, but with Ruby. When you look at your code:
def encrypt_password
self.encrypted_password = encrypt(password)
end
it will be translated by Ruby into:
self.encrypted_password =
is a method call to encrypted_password=
method.
- This method is generated by Rails on the fly, because there exists a database column with the same name.
encrypt(password)
contains 2 methods calls.
password
calls the method password
which is a real attribute of the model by the declaration attr_accessor :password
. This declaration creates two methods:
password
: getter of the attribute
password=
: setter of the attribute
See the explanation of @Sergio_Tulentsev how the getter could be hidden by a local variable (which is not the case in your implementation, there is no local variable).
- Calls the method
encrypt
with the return value of method call password
.
So the use of self.
makes it explicit that you have (all the time) a method call, you don't access the attribute directly. If you want to do that, you have to use @password = <some value>
inside an instance method, but I like the style with self.password = <some value>
much more.
I hope it is clear now how your code is interpreted.
setter method => use self
Use self
when you need to write something.
In other words, when you need to assign a value.
getter method => don't use self
And without self
when you need to read something.
When you need to read a value.
for instance:
def write_name(name)
self.name = name
end
def read_name
name
end
In your case, the virtual attribute password
isn't prefixed with the self
keyword because it is only read(getter).
encrypted_password
is what will be stored in the database, it is written in the db (setter). Thus the use of self
.
Edit:
Michael HARTL has the same explanation about the very same case:
(Of course, as we’ve noted, the self is not optional when assigning to an attribute, so we have to write self.encrypted_password in this case.)
http://ruby.railstutorial.org/chapters/modeling-and-viewing-users-two#sec:an_active_record_callback
(last lines of 7.1.3)