2012-07-12 4 views
5

値が存在しなくても、属性に値を割り当てるカスタムアクセサメソッドを持っています。my_attr属性は、空白値が指定されていない限り、指定された値とマージされるべきシリアル化されたハッシュですが指定されている場合は、現在の値を空白の値に設定します。 (そこに彼らがどうあるべきかの値であることを確認するチェックを追加されますが、簡潔にするため削除され、彼らは私の質問の一部ではないとして。)私のセッターは、次のように定義されます。このコードのようにうまく機能Railsモデルでselfの値は何ですか?また、明白なインスタンスメソッドが利用できない理由は何ですか?

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 

-isですが、self.write_attribute()を使用した場合は表示されません。私は、次のエラーを取得する:

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

は、私の質問は、このようにしている:インスタンスに利用できるwrite_attributeを持っているより論理的と思われるので、なぜそれがクラスにのみ使用可能で、インスタンスにない? RubyやRails(またはその両方)の自己の私の基本的な知識に欠けているものはありますか?

答えて

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.

関連する問題