Rails 模型中 self 的值是什么,为什么没有明显的实例方法可用? [英] What is the value of self in a Rails model and why aren't obvious instance methods available?

查看:45
本文介绍了Rails 模型中 self 的值是什么,为什么没有明显的实例方法可用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 rails 3.1.6 应用程序中有一个自定义访问器方法,即使该值不存在,它也会为属性分配一个值.my_attr 属性是一个序列化的哈希,除非为空白,否则应与给定的值合并value 被指定,在这种情况下,它会将当前值设置为空白值.(添加了检查以确保值应该是什么,但为了简洁起见被删除,因为它们不是我的问题的一部分.)我的 setter 被定义为:

I have a custom accessor method in my rails 3.1.6 app that assigns a value to an attribute, even if the value is not present.The my_attr attribute is a serialized Hash which should be merged with the given value unless a blank value is specified, in which case it will set the current value to a blank value. (There are added checks to make sure the values are what they should be, but are removed for brevity, as they are not part of my question.) My setter is defined as:

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() 时则不行.然后我收到以下错误:

This code works well as-is, but not when I use self.write_attribute(). I then get the following error:

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

我的问题是这样的:让 write_attribute 对实例可用似乎更合乎逻辑,那么为什么它只对类可用而对实例可用?我对 Ruby 或 Rails(或两者)self 的基本知识是否缺乏?

My questions are thus: It seems more logical to have write_attribute available to an instance, so why is it only available to the class and not to the instance? Is there something lacking in my fundamental knowledge of self in Ruby or Rails (or both)?

推荐答案

实例方法的内部 self 就是那个实例.但是,当您调用具有显式接收器的方法时,ruby 的可见性控制会启动并禁止调用私有方法.

Inside of an instance method self is that instance. However, when you call a method with explicit receiver, then ruby's visibility control kicks in and forbids invocation of the private method.

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.

If you want to call private methods, use implicit receiver or send.

self.send :private_method

更新

摘自 ruby 元编程书籍.

既然您了解了 self,您就可以对 Ruby 的 private 关键字进行重新审视.私有方法由一个简单的规则控制:您不能使用显式接收器调用私有方法.换句话说,每次调用私有方法时,它都必须在隐式接收者——self 上.让我们看一个角落案例:

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 [...]

您可以通过删除 self 关键字使此代码工作.

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."

您可能会发现 Ruby 的私有方法令人困惑——尤其是如果您来自 Java 或 C#,私有方法的行为非常不同.当你有疑问时,回到私人规则,一切都会有意义.如果两个对象共享同一个类,对象 x 可以调用对象 y 上的私有方法吗?答案是否定的,因为无论你属于哪个类,你仍然需要一个显式的接收者来调用另一个对象的方法.您可以调用从超类继承的私有方法吗?答案是肯定的,因为您不需要显式接收器来调用自己的继承方法.

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.

这篇关于Rails 模型中 self 的值是什么,为什么没有明显的实例方法可用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆