Reputation: 3818
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?
Upvotes: 5
Views: 3879
Reputation: 15525
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.
Upvotes: 2
Reputation: 27463
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)
Upvotes: 0
Reputation: 230296
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
.
Upvotes: 8