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

pez*_*ser 14 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
Run Code Online (Sandbox Code Playgroud)

mol*_*olf 13

def before_create
   self.hashed_password = User.hash_password(self.password)
end
Run Code Online (Sandbox Code Playgroud)

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

如果替换User.hash_passwordself.hash_password,Ruby会抱怨NoMethodError,因为类中没有名称hash_password存在的实例方法User.不过你可以用它替换它self.class.hash_password.

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

所述self的方法中定义(def self.hash_password)使hash_password一个类的方法,而不是一个实例方法.在这种情况下,self指的是.在实例方法的上下文中,self指的是一个实例.


Cor*_*ook 12

您要问的是类方法和实例方法之间的区别.

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

class Klass
  def Klass.method_name
    ..
  end
end
Run Code Online (Sandbox Code Playgroud)

这跟做的一样:

class Klass
  def self.method_name
    ..
  end
end 
Run Code Online (Sandbox Code Playgroud)

或者首选的红宝石成语:

class Klass
  class << self
    def method_name
      ..
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

如果Klass已经宣布你也可以做..

def Klass.method_name
  ..
end
Run Code Online (Sandbox Code Playgroud)

要么:

class << Klass
  def method_name
    ..
  end
end
Run Code Online (Sandbox Code Playgroud)

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

Klass.extend(Module.new { def method_name; puts 'ducky'; end })
Run Code Online (Sandbox Code Playgroud)

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

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

Person.find(1) 
Run Code Online (Sandbox Code Playgroud)

和'save'这样的实例方法,它们对单个对象进行操作

person = Person.find(1)
...
person.save
Run Code Online (Sandbox Code Playgroud)

在我正在处理的当前项目中,我有一个包含数据馈送的模型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
Run Code Online (Sandbox Code Playgroud)