试图了解Ruby中self.method_name与Classname.method_name的使用

时间:2009-05-14 14:52:43

标签: ruby

我正在尝试了解何时使用self.method_name与何时使用Classname.method_name。

在下面的示例中,为什么“before_create”需要引用“User.hash_password”而不是“self.hash_password”或只是“hash_password”?

由于我们已经在User类中,我认为before_create方法会“知道”“hash_password”是其自己的类的成员,并且不需要任何特殊语法来引用它。

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

3 个答案:

答案 0 :(得分:13)

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

在此示例中,User.hash_password调用 hash_password上的User方法,而self.hashed_password=调用hashed_password=方法 User此特定实例

如果将User.hash_password替换为self.hash_password,Ruby会抱怨NoMethodError,因为类hash_password中不存在User名称的实例方法}。不过,您可以将其替换为self.class.hash_password

如果用self.hashed_password=替换hashed_password=,Ruby将创建一个名为hashed_password的局部变量,而不是调用实例方法hashed_password=。如果要调用属性编写器,则需要显式添加self

方法定义中的selfdef self.hash_password)使hash_password成为类方法而不是实例方法。在此上下文中,self指的是。在实例方法的上下文中,self引用实例

答案 1 :(得分:12)

您正在询问类方法和实例方法之间的区别。

有几种方法可以定义类方法:

class Klass
  def Klass.method_name
    ..
  end
end

与做:

相同
class Klass
  def self.method_name
    ..
  end
end 

或首选的红宝石成语:

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

如果已宣布Klass,你也可以这样做..

def Klass.method_name
  ..
end

或:

class << Klass
  def method_name
    ..
  end
end

或者您甚至可以使用Module #extend:

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

就像你会向对象添加单例方法一样。实际上,类方法是在类级别上运行的单例方法。

在rails ActiveRecord中,你有一个类方法'find'可以在任何Model上使用:

Person.find(1) 

和'save'等实例方法对单个对象进行操作

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

在我正在处理的当前项目中,我有一个包含数据源的模型Feed。我需要定期运行一个更新所有Feed的方法,这样我就有了一个fetch_all方法来完成这个。

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

答案 2 :(得分:1)

我还没有深入研究Ruby,但是根据你的描述,我会说hash_password是一个静态方法,或者能够以静态方式使用。