2012-07-12 26 views
5

我在我的rails 3.1.6應用程序中有一個自定義的存取器方法,它爲值賦給一個屬性,即使這個值不存在。my_attr屬性是一個序列化的哈希,它應該與給定的值合併,除非一個空值被指定,在這種情況下,它會將當前值設置爲空白值。 (有加檢查,以確保該值應該是什麼,但爲了簡便起見被刪除,因爲它們不是我的問題的一部分。)我的二傳手定義爲:Rails模型中自我的價值是什麼?爲什麼不提供明顯的實例方法?

def my_attr=(new_val) 
    cur_val = read_attribute(:my_attr) #store current value 

    #make sure we are working with a hash, and reset value if a blank value is given 
    write_attribute(:my_attr, {}) if (new_val.nil? || new_val.blank? || cur_val.blank?) 

    #merge value with new 
    if cur_val.blank? 
    write_attribute(:my_attr, new_val) 
    else 
    write_attribute(:my_attr,cur_val.deep_merge(new_val)) 
    end 
    read_attribute(:my_attr) 
end 

此代碼的工作以及 - 是,但不是當我使用self.write_attribute()時。然後我得到了以下錯誤:

NoMethodError: 
     private method `write_attribute' called for #<MyModel:0x00000004f10528> 

我的問題是這樣的:它似乎更符合邏輯有可用實例write_attribute,那麼爲什麼只對類和的實例?在Ruby或Rails(或兩者)中,我的基本知識self中是否存在某些缺陷?

回答

11

在實例方法self裏面是那個實例。但是,當你使用顯式接收者調用方法時,ruby的可見性控制就會啓動並禁止調用私有方法。

class Foo 
    def implicit 
    self # => #<Foo:0x007fc019091060> 
    private_method 
    end 

    def explicit 
    self # => #<Foo:0x007fc019091060> 
    self.private_method 
    end 

    private 
    def private_method 
    "bar" 
    end 
end 

f = Foo.new 
f.implicit # => "bar" 
f.explicit # => 
# ~> -:9:in `explicit': private method `private_method' called for #<Foo:0x007fc019091060> (NoMethodError) 
# ~> from -:25:in `<main>' 

如果要調用私有方法,請使用隱式接收方或send

self.send :private_method 

更新

ruby metaprogramming book的摘錄。

What private Really Means

Now that you know about self, you can cast a new light over Ruby’s private keyword. Private methods are governed by a single simple rule: you cannot call a private method with an explicit receiver. In other words, every time you call a private method, it must be on the implicit receiver—self. Let’s see a corner case:

class C 
    def public_method 
    self.private_method 
    end 
    private 
    def private_method; end 
end 
C.new.public_method 

⇒ NoMethodError: private method ‘private_method' called [...] 

You can make this code work by removing the self keyword.

This contrived example shows that private methods come from two rules working together: first, you need an explicit receiver to call a method on an object that is not yourself, and second, private methods can be called only with an implicit receiver. Put these two rules together, and you’ll see that you can only call a private method on yourself. You can call this the 「private rule.」

You could find Ruby’s private methods perplexing—especially if you come from Java or C#, where private behaves very differently. When you’re in doubt, just go back to the private rule, and everything will make sense. Can object x call a private method on object y if the two objects share the same class? The answer is no, because no matter which class you belong to, you still need an explicit receiver to call another object’s method. Can you call a private method that you inherited from a superclass? The answer is yes, because you don’t need an explicit receiver to call inherited methods on yourself.

相關問題