在不使用 self 的情况下从模型设置属性不起作用
设备模型具有以下属性:名称、版本和全名
全名是名称+版本:
class Device < ActiveRecord::Base
def prepare
full_name = (!show_version || version.nil?)? name : name + " " + version.to_s
end
end
当我执行以下操作时:
d = Device.new :name => "iPhone", :version => "4"
d.prepare
d.full_name # get nil
“full_name”属性为nil
当我使用“self”时,它有效:
class Device < ActiveRecord::Base
def prepare
self.full_name = (!show_version || version.nil?)? name : name + " " + version.to_s
end
end
执行“prepare”我得到“ iPhone 4”为“full_name”属性。
这里的一些人告诉我,避免在类方法中使用“self”是一个好方法。 但这会带来麻烦。
问题是 - 为什么不使用“self”它就不起作用?
Device model has following attributes: name, version and full_name
Full name is name + version:
class Device < ActiveRecord::Base
def prepare
full_name = (!show_version || version.nil?)? name : name + " " + version.to_s
end
end
When i do following:
d = Device.new :name => "iPhone", :version => "4"
d.prepare
d.full_name # get nil
I get nil for "full_name" attribute
When I'm using "self", it works:
class Device < ActiveRecord::Base
def prepare
self.full_name = (!show_version || version.nil?)? name : name + " " + version.to_s
end
end
Doing "prepare" i get "iPhone 4" for "full_name" attribute.
Some people here told me, that it's a good manner to avoid using "self" inside class methods.
But this brings trouble.
The question is - why it does't works without using "self" ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在这些情况下你必须使用 self,我不认为这是一个麻烦。如果您使用
self
,那么解释器就会知道您引用了对象的属性。如果您不使用 self ,则意味着它只是一个局部变量,在方法完成后不会存储在任何地方。这是正常行为。您还可以使用 self[:full_name]= ... 作为 setter 方法,但在这种情况下并不重要。更新
@AntonAL
因为 getter 方法无需
self.
即可识别。当您尝试使用
name
属性时,解释器将在当前方法中查找局部变量。如果没有找到,则查找实例属性。示例:iPhone
将存储在对象实例的name
属性中。方法完成后,iPod
将丢失。In these cases you have to use self, I don't think it's a trouble. If you are using
self
then the interpreter will know that you refer to the object's attribute. If you don't useself
it means that it's just an local variable which is not stored anywhere after the method finishes.That's the normal behavior. You can also useself[:full_name]= ...
as a setter method, but in this case doesn't really matter.Update
@AntonAL
Because the getter methods are recognized without the
self.
.When you try to use the
name
attribute, the interpreter will look for a local variable within the current method. If doesn't finds then looks for an instance attribute. Example:And
iPhone
will be stored in your object instance'sname
attribute. AndiPod
will be lost after the method finishes.当您使用setter时,您需要使用
self
,否则Ruby会将其解释为正在定义的新局部变量full_name
。对于getters,我们不需要调用
self
,因为Ruby首先搜索局部变量full_name
,当它没有局部变量full_name
时,它将搜索方法full_name
并获取 getter。如果您定义了局部变量full_name
,它将返回局部变量的值。这在 上一个问题
When you use setters, you need to use
self
because otherwise Ruby will interpret it as a new local variablefull_name
being defined.For getters, we dont need to call
self
because Ruby first search for a local variablefull_name
and when it does not have a local variablefull_name
, it will search for a methodfull_name
and will get the getter. If you have a local variable definedfull_name
, it will return the value of local variable.This is explained better in a previous question
这是预料之中的,因为这就是 ActiveRecord 的设计工作原理。如果您需要设置任意属性,那么您必须使用不同类型的对象。
例如,Ruby 提供了一个名为
允许您创建可以分配任意键和值的对象。如果您想从没有 self 的属性中获取值,它将为您提供具有实例全局变量属性的 OpenStruct 类的实例。但如果你想设置新属性,它会使用新属性创建 OpenStruct 类的新实例。如果没有 self,您将拥有旧的 OpenStruct 对象,它没有属性,并且会给您带来错误。
您可能需要使用此类库,然后仅在需要保存到数据库时将对象转换为相应的 ActiveRecord 实例。
不要尝试对 ActiveRecord 进行建模以使其按照您刚才描述的方式运行,因为它根本就不是为了以这种方式运行而设计的
This is expected because it's how ActiveRecord works by design. If you need to set arbitrary attributes, then you have to use a different kind of objects.
For example, Ruby provides a library called
that allows you to create objects where you can assign arbitrary key and values. If you want get value from attribute without self, it's will give you instance of class OpenStruct with instance global variable attribute. But if you want set new attribute, it`s create new instance of class OpenStruct with new attributes. Without self you will have are old OpenStruct object which don't have attribute and will gave you error.
You may want to use such library and then convert the object into a corresponding ActiveRecord instance only when you need to save to the database.
Don't try to model ActiveRecord to behave as you just described because it was simply not designed to behave in that way