2009-05-14 15 views
13

Estoy tratando de entender cuándo usar self.method_name frente a cuándo usar Classname.method_name.Intentando entender el uso de self.method_name vs. Classname.method_name en Ruby

En el ejemplo siguiente, ¿por qué "before_create" necesita hacer referencia a "User.hash_password" en lugar de "self.hash_password" o simplemente "hash_password"?

Como ya estamos en la clase de usuario, pensé que el método before_create "sabría" que "hash_password" es un miembro de su propia clase y no necesitaría ninguna sintaxis especial para referirse a él.

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 

Respuesta

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

En este ejemplo User.hash_password, llama al método hash_password en la claseUser, mientras que self.hashed_password= llama al método hashed_password= en este particular ejemplo de User.

Si reemplaza User.hash_password con self.hash_password, Ruby se quejaba con un NoMethodError, porque ningún método de instancia con el nombre de hash_password existe en la clase User. Sin embargo, podría reemplazarlo por self.class.hash_password.

Si reemplaza con self.hashed_password= simplemente hashed_password=, Ruby crearía una variable local llamada hashed_password, en lugar de llamar al método de instancia hashed_password=. Debe agregar explícitamente self si desea llamar a escritores de atributos.

La self en la definición del método (def self.hash_password) hace que hash_password sea un método de clase en lugar de un método de instancia. En este contexto, self se refiere a la clase . En el contexto de un método de instancia, self se refiere a una instancia .

+0

Dado que las últimas líneas definen def self.hash_password (contraseña), pensé que self.hash_contraseña hacía referencia a este método. Pero está diciendo que self.hash_password obtendría NoMethodError, aunque la definición del método diga "self". No puedo referirme a esto con "yo". ¡Confuso! –

+0

self.hashed_password = llama a un escritor de atributos? Pero no definí un escritor de atributos. ¿Se creó uno automáticamente? –

+0

self.hashed_password = probablemente esté definido por ActiveRecord para usted, si tiene una columna de base de datos llamada 'hashed_password'. – molf

1

todavía tengo que ahondar en Ruby, pero a partir de su descripción diría que hash_password es un método estático o es capaz de ser utilizado de una manera estática.

+3

correcto. En ruby, los métodos estáticos se llaman métodos de clase –

12

Estás preguntando la diferencia entre un método de clase y un método de instancia.

Hay algunas maneras de definir un método de clase:

class Klass 
    def Klass.method_name 
    .. 
    end 
end 

que es lo mismo que hacer:

class Klass 
    def self.method_name 
    .. 
    end 
end 

o el lenguaje de rubí preferido:

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

Si Klass ya está declarado que también puedes hacer ...

def Klass.method_name 
    .. 
end 

o:

class << Klass 
    def method_name 
    .. 
    end 
end 

o incluso se podría utilizar el módulo # extienden:

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

al igual que se añada un método singleton a un objeto. De hecho, los métodos de clase son métodos únicos que operan en el nivel de clase.

En los carriles ActiveRecord por ejemplo, tiene un método de clase 'encontrar' que se puede utilizar en cualquier modelo:

Person.find(1) 

y de instancia métodos como 'salvar', que opera en el objeto individual

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

En el proyecto actual en el que estoy trabajando tengo un feed modelo que contiene feeds de datos. Periódicamente necesito ejecutar un método que actualice todos los feeds, así que tengo un método fetch_all que lo logra.

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 
Cuestiones relacionadas