Попытка понять использование self.method_name vs. Classname.method_name в 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
Ответы
Ответ 1
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
, потому что в классе User
не существует метода экземпляра с именем hash_password
. Однако вы можете заменить его на self.class.hash_password
.
Если вы замените self.hashed_password=
просто hashed_password=
, Ruby создаст локальную переменную с именем hashed_password
, а не вызовет метод экземпляра hashed_password=
. Вам нужно явно добавить self
, если вы хотите вызвать авторов атрибутов.
self
в определении метода (def self.hash_password
) делает hash_password
метод класса вместо метода экземпляра. В этом контексте self
относится к классу. В контексте метода экземпляра self
относится к экземпляру.
Ответ 2
Вы задаете разницу между методом класса и методом экземпляра.
Существует несколько способов определения метода класса:
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
или вы даже можете использовать расширение модуля #:
Klass.extend(Module.new { def method_name; puts 'ducky'; end })
Похоже, вы добавили метод singleton к объекту. На самом деле методы класса - это одноэлементные методы, которые работают на уровне класса.
В рельсах ActiveRecord, например, у вас есть метод класса "find", который вы можете использовать на любой модели:
Person.find(1)
и методы экземпляра, такие как "save", который работает с отдельным объектом
person = Person.find(1)
...
person.save
В текущем проекте, над которым я работаю, у меня есть модель 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
Ответ 3
Мне еще предстоит вникать в Ruby, но из вашего описания я бы сказал, что hash_password является статическим методом или может использоваться статически.