pez_dispenser
pez_dispenser

Reputation: 4464

Trying to understand use of self.method_name vs. Classname.method_name in Ruby

I'm trying to understand when to use self.method_name vs. when to use Classname.method_name.

In the example below, why does "before_create" need to reference "User.hash_password" instead of "self.hash_password" or just "hash_password"?

Since we are in the User class already, I thought the before_create method would "know" that "hash_password" is a member of its own class and would not need any special syntax to refer to it.

require 'digest/sha1'

class User < ActiveRecord::Base

  attr_accessor :password
  attr_accessible :name, :password

  validates_presence_of :name, :password
  validates_uniqueness_of :name

  def before_create
    self.hashed_password = User.hash_password(self.password)
  end

  def after_create
    @password = nil
  end

  def self.login(name, password)
    hashed_password = hash_password(password || "")
    self.find(:first, :conditions => ["name = ? and hashed_password = ?", name, hashed_password])
  end

  def try_to_login
    User.login(self.name, self.password)
  end

  private

  def self.hash_password(password)
    Digest::SHA1.hexdigest(password)
  end

end

Upvotes: 14

Views: 3891

Answers (3)

molf
molf

Reputation: 75035

def before_create
   self.hashed_password = User.hash_password(self.password)
end

In this example, User.hash_password calls the hash_password method on the class User, whereas self.hashed_password= calls the hashed_password= method on this particular instance of User.

If you replace User.hash_password with self.hash_password, Ruby would complain with a NoMethodError, because no instance method by the name of hash_password exists in the class User. You could replace it with self.class.hash_password, though.

If you replace self.hashed_password= with simply hashed_password=, Ruby would create a local variable named hashed_password, rather than call the instance method hashed_password=. You need to explicitly add self if you want to call attribute writers.

The self in the method definition (def self.hash_password) makes hash_password a class method instead of an instance method. In this context, self refers to the class. In the context of an instance method, self refers to an instance.

Upvotes: 13

Corban Brook
Corban Brook

Reputation: 21378

You are asking the difference between a class method and an instance method.

There are a few ways of defining a class method:

class Klass
  def Klass.method_name
    ..
  end
end

which is the same as doing:

class Klass
  def self.method_name
    ..
  end
end 

or the preferred ruby idiom:

class Klass
  class << self
    def method_name
      ..
    end
  end
end

If Klass is already declared you can also do..

def Klass.method_name
  ..
end

or:

class << Klass
  def method_name
    ..
  end
end

or you could even use Module#extend:

Klass.extend(Module.new { def method_name; puts 'ducky'; end })

Much like you would add a singleton method to an object. In fact class methods are singleton methods which operate on the class level.

In rails ActiveRecord for example you have a class method 'find' which you can use on any Model:

Person.find(1) 

and instance methods like 'save' which operates on the individual object

person = Person.find(1)
...
person.save

In the current project I am working on I have a model Feed which contains data feeds. Periodically I need to run a method which updates all the feeds so i have an fetch_all method which accomplishes this.

class Feed < ActiveRecord::Base 

  // class method Feed.fetch_all
  def self.fetch_all
    Feed.all.each do |feed|
      feed.fetch_value
    end
  end

  // instance method
  def fetch_value
    // grabs updated value and saves 
  end
end

Upvotes: 13

Randolpho
Randolpho

Reputation: 56448

I have yet to delve into Ruby, but from your description I'd say that hash_password is a static method or is capable of being used in a static manner.

Upvotes: 1

Related Questions