我的rails 3.1.6应用程序中有一个自定义访问器方法,即使该值不存在,也会为属性赋值.my_attr属性是一个序列化的哈希值,除非有空白,否则应与给定值合并指定了值,在这种情况下,它会将当前值设置为空值。 (增加了检查以确保它们应该是值,但为了简洁起见,将其删除,因为它们不是我的问题的一部分。)我的setter定义为:
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 的基本知识缺乏某些东西吗?
答案 0 :(得分: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的私人关键词施加新的启示。私有方法由一个简单的规则控制:您不能使用显式接收器调用私有方法。换句话说,每次调用私有方法时,它必须位于隐式receiver-self上。让我们看一个角落案例:
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 [...]
您可以通过删除self关键字来使此代码生效。
这个人为的例子表明私有方法来自两个一起工作的规则:首先,你需要一个显式接收器来调用一个不是你自己的对象的方法,其次,私有方法只能用一个隐式接收器来调用。将这两个规则放在一起,您将看到您只能自己调用私有方法。你可以称之为“私人规则”。
你可能会发现Ruby的私有方法令人困惑 - 特别是如果你来自Java或C#,其中私有行为的表现非常不同。如果您有疑问,只需回到私人规则,一切都会有意义。如果两个对象共享同一个类,对象x可以在对象y上调用私有方法吗?答案是否定的,因为无论你属于哪个类,你仍然需要一个明确的接收器来调用另一个对象的方法。你可以调用从超类继承的私有方法吗?答案是肯定的,因为您不需要显式接收器来自行调用继承的方法。