Kichang  Yang
Kichang Yang

Reputation: 913

Difference between self.foobar and foorbar in Rails 3.x? Rails couldn't find a method without 'self.' in the definition

When I omitted 'self.' from the method definition, Rails couldn't find a method.

undefined method `authenticate' for #<Class:0x00000103b8c640>
...
app/controllers/sessions_controller.rb:6:in `create'

Here is the snippet from the source,

class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation

attr_accessor :password

before_save :encrypt_password
...
def encrypt_password
  if password.present?
    self.password_salt = BCrypt::Engine.generate_salt
    self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
  end
end

def authenticate(email, password)
  user = find_by_email(email)
  if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
    user
  else
    nil
  end
end

and authenticate() is called from SessionController

class SessionConstroller < ApplicationController

def create
  user = User.authenticate(params[:email], params[:password])
  ...
end

When I add 'self.' to the definition of authenticate(), it works without error.

What's the difference between adding 'self.' and nothing to the method definition in Rails 3.x?

self.authenticate(...)

authenticate(...)

Upvotes: 0

Views: 140

Answers (2)

Fivell
Fivell

Reputation: 11929

The keyword self in Ruby gives you access to the current object – the object that is receiving the current message. self.authenticate in the above example will be invoked by the (current) object, User. While authenticate will be invoked by the instance object, (User.new)

Upvotes: 0

Peter
Peter

Reputation: 132247

Adding self to the method definition makes it a class method rather than an instance method. So when you try and call User.authenticate, it only works if you defined the method on the class rather than for instances of User.

Like this:

class User
  puts self.inspect   # would return "User"

  def self.authenticate
    puts self.inspect  # also returns "User" when called like User.authenticate
  end

  def authenticate
    puts self   # will only work for instances of User.
  end
end

Try playing around with small example codes like this, rather than straight away within the larger context.

Upvotes: 1

Related Questions