2009-05-14 7 views
13

Sto cercando di capire quando utilizzare self.method_name e quando utilizzare Classname.method_name.Tentativo di comprendere l'uso di self.method_name rispetto a Classname.method_name in Ruby

Nell'esempio seguente, perché "before_create" deve fare riferimento a "User.hash_password" anziché a "self.hash_password" o semplicemente "hash_password"?

Dato che siamo già nella classe User, ho pensato che il metodo before_create avrebbe "saputo" che "hash_password" è un membro della sua stessa classe e non avrebbe bisogno di alcuna sintassi speciale per farvi riferimento.

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 

risposta

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

In questo esempio, User.hash_password chiama il metodo hash_password sulla classeUser, mentre self.hashed_password= chiama il metodo hashed_password= su fattispecie di User.

Se si sostituisce User.hash_password con self.hash_password, Ruby si lamentava con un NoMethodError, perché nessun metodo di istanza con il nome di hash_password esiste nella classe User. Potresti sostituirlo con self.class.hash_password, però.

Se si sostituisce self.hashed_password= con semplicemente hashed_password=, Ruby creerebbe una variabile locale denominata hashed_password, piuttosto che chiamare il metodo di istanza hashed_password=. È necessario aggiungere esplicitamente self se si desidera chiamare gli autori di attributi.

Il self nella definizione del metodo (def self.hash_password) rende hash_password un metodo di classe anziché un metodo di istanza. In questo contesto, self si riferisce alla classe . Nel contesto di un metodo di istanza, self fa riferimento a un'istanza .

+0

Poiché le ultime righe definiscono def self.hash_password (password), ho pensato che self.hash_password faceva riferimento a questo metodo. Ma stai dicendo che self.hash_password otterrebbe un NoMethodError - anche se la definizione del metodo dice "self". Non posso riferirmi a "sé". Confusione! –

+0

self.hashed_password = chiama un attributo writer? Ma non ho definito uno scrittore di attributi. È stato creato automaticamente? –

+0

self.hashed_password = è probabilmente definito da ActiveRecord per te, se hai una colonna di database chiamata 'hashed_password'. – molf

1

Devo ancora approfondire Ruby, ma dalla tua descrizione direi che hash_password è un metodo statico o è in grado di essere utilizzato in maniera statica.

+3

giusto. In ruby, i metodi statici sono chiamati metodi di classe –

12

Stai chiedendo la differenza tra un metodo di classe e un metodo di istanza.

Ci sono alcuni modi per definire un metodo di classe:

class Klass 
    def Klass.method_name 
    .. 
    end 
end 

che è la stessa come fare:

class Klass 
    def self.method_name 
    .. 
    end 
end 

o il rubino preferito linguaggio:

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

Se Klass è già dichiarato che puoi anche farlo ..

def Klass.method_name 
    .. 
end 

o:

class << Klass 
    def method_name 
    .. 
    end 
end 

o si potrebbe anche utilizzare il modulo # estendono:

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

proprio come si farebbe aggiungere un metodo Singleton a un oggetto. In effetti i metodi di classe sono metodi singleton che operano a livello di classe.

in Rails ActiveRecord ad esempio si dispone di un metodo di classe 'find', che si può utilizzare su qualsiasi modello:

Person.find(1) 

e istanze metodi come 'salvare' che opera sul singolo oggetto

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

Nel progetto corrente su cui sto lavorando, ho un feed modello che contiene feed di dati. Periodicamente ho bisogno di eseguire un metodo che aggiorni tutti i feed così ho un metodo fetch_all che lo compie.

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 
Problemi correlati