2009-05-14 8 views
13

self.method_nameを使用するときとClassname.method_nameを使用するときを理解しようとしています。Rubyでself.method_nameとClassname.method_nameの使用を理解しようとしています

以下の例では、「before_create」は「self.hash_password」または「hash_password」の代わりに「User.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 

答えて

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

self.hashed_password=Userのこの特定のインスタンスhashed_password=メソッドを呼び出すのに対し、User.hash_passwordは、クラスUserhash_passwordメソッドを呼び出します。

あなたはself.hash_passwordUser.hash_passwordを交換した場合hash_passwordの名前で何のインスタンスメソッドは、クラスUserに存在しないため、Rubyは、NoMethodErrorと文句を言うでしょう。あなたはself.class.hash_passwordと置き換えることができます。

あなたは、単にhashed_password=self.hashed_password=を交換した場合、Rubyはhashed_passwordという名前のローカル変数を作成するのではなく、インスタンスメソッドhashed_password=を呼び出します。属性ライターを呼び出す場合は、明示的にselfを追加する必要があります。

メソッド定義(def self.hash_password)のselfは、hash_passwordをインスタンスメソッドではなくクラスメソッドにします。この文脈において、selfは、クラスを指す。インスタンスメソッドのコンテキストでは、selfインスタンスを指します。

+0

最後の数行はdef self.hash_password(password)を定義しているので、self.hash_passwordはこのメソッドを参照していると考えました。しかし、self.hash_passwordはNoMethodErrorを取得すると言っています。たとえメソッド定義に「self」と書かれています。私はそれを「自己」と呼ぶことはできません。混乱している! –

+0

self.hashed_pa​​ssword =属性ライターを呼び出しますか?しかし、私は属性ライターを定義しませんでした。 1つは自動的に作成されましたか? –

+0

「hashed_pa​​ssword」という名前のデータベース列がある場合は、self.hashed_pa​​ssword =おそらくActiveRecordによって定義されます。 – molf

1

私は、Ruby掘り下げるためにまだ持っているが、あなたの説明から私はHASH_PASSWORDが静的メソッドであるか、静的な方法で使用されることが可能であることを言うと思います。この例では

+3

そうです。 Rubyでは静的メソッドはクラスメソッドと呼ばれます –

12

あなたはクラスメソッドとインスタンスメソッドの違いを尋ねています。

class Klass 
    def self.method_name 
    .. 
    end 
end 

または優先ルビーのイディオム:

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

の場合をやってと同じです

class Klass 
    def Klass.method_name 
    .. 
    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 }) 

多くがオブジェクトにシングルトンメソッドを追加します。実際、クラスメソッドは、クラスレベルで動作するシングルトンメソッドです。レールのActiveRecordでは

例えばあなたは、クラスメソッドは、任意のモデルに使用できる「見つける」を持っている:

Person.find(1) 

と個々のオブジェクト

person = Person.find(1) 
... 
person.save 
上で動作する「保存」などのインスタンスメソッド

現在作業中のプロジェクトでは、データフィードを含むモデルフィードがあります。定期的に私はすべてのフィードを更新するメソッドを実行する必要があるので、これを実現する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 
関連する問題