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?
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.
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.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 attributepassword=
: setter of the attributeSee 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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With