Kvass Kvass - 1 year ago 81
Ruby Question

Rails -- self vs. @

I am following Michael Hartl's RoR tutorial, and it is covering the basics of password encryption. This is the User model as it currently stands:

class User < ActiveRecord::Base
attr_accessor :password

attr_accessible :name, :email,: password, :password_confirmation

email_regex = /^[A-Za-z0-9._+-]+@[A-Za-z0-9._-]+\.[A-Za-z0-9._-]+[A-Za-z]$/
#tests for valid email addresses.

validates :name, :presence => true,
:length => {:maximum => 50}
validates :email, :presence => true,
:format => {:with => email_regex},
:uniqueness => {:case_sensitive => false}
validates :password, :presence => true,
:length => {:maximum => 20, :minimum => 6},
:confirmation => true

before_save :encrypt_password


def encrypt_password
self.encrypted_password = encrypt(password)

def encrypt(string)

I posted a previous question about
not working, and it turns out that what I had accidentally done is written my encrypt_password as:

def encrypt_password
@encrypted_password = encrypt(password)

I understand that if self.encrypted_password sets the encrypted_password attribute, but why does @encrypted_password not do that as well? In the response to the previous post about
not working someone said that the instance variable was "forgotten" after the method ended with the way I had originally coded it -- why was this the case? Can someone please explain how self and @ work differently in the context of the code above?

NOTE: I already took a look at the posts here and here, but they both say that "self" is calling the
attribute =
method, and I don't even understand how that method could exist here since I never created it or declared the encrypted_password w/
. So I am still confused, and this is not a re-posting of those questions.

Answer Source

The accessors for encrypted_password have been automatically added by Rails for you because a field by that name exists in the users table.

Any field you add to a table will be automatically made available via self.field_name.

Here is where Michael Hartl's tutorial creates the encrypted_password field in the users table.

Also look at the user_spec.rb (Listing 7.3) in the linked page, where the author is testing for the presence of the encrypted_password field.


As @mu points out, the @ is used for Ruby instance variables (aka "iv"). But encrypted_password is an "attribute" defined by Rails, and is not an instance variable.

If you run User.find(1).instance_variables, you will see that there is an iv called @attributes, which is of type Hash.

Inside that iv is where the encrypted_password is stored. Rails has defined accessor methods for encrypted_password, which gets/sets the data for that attribute in the @attributes Hash.

Note that you could also get/set the data via @attributes["encrypted_password"] called from within the User class (but the accessor methods are convenient way to do just that).

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download