设备型号具有以下属性:name,version和full_name
全名是name + version:
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当我使用“自我”时,它有效:
class Device < ActiveRecord::Base
def prepare
self.full_name = (!show_version || version.nil?)? name : name + " " + version.to_s
end
end
做“准备”我得到“iPhone 4”的“full_name”属性。
有些人告诉我,避免在课堂方法中使用“自我”是一种好方法。 但这会带来麻烦。
问题是 - 为什么不使用“自我”就行不通?
答案 0 :(得分:13)
在这些情况下你必须使用自我,我不认为这是一个麻烦。如果您使用self
,那么解释器将知道您引用了对象的属性。如果你不使用self
,这意味着它只是一个局部变量,在方法完成后没有存储在任何地方。这是正常的行为。您也可以使用self[:full_name]= ...
作为setter方法,但在这种情况下并不重要。
<强>更新强>
@AntonAL
因为在没有self.
的情况下识别了getter方法。
当您尝试使用name
属性时,解释器将在当前方法中查找局部变量。如果未找到,则查找实例属性。例如:
def your_method
self.name = 'iPhone'
puts name
#iPhone
name = 'iPod'
puts name
#iPod
puts self.name
#iPhone
end
iPhone
将存储在对象实例的name
属性中。方法完成后iPod
将丢失。
答案 1 :(得分:13)
使用setter时,需要使用self
,否则Ruby会将其解释为正在定义的新局部变量full_name
。
对于getter,我们不需要调用self
,因为Ruby首先搜索局部变量full_name
,当它没有局部变量full_name
时,它将搜索一个方法full_name
并获得吸气剂。如果您定义了一个局部变量full_name
,它将返回局部变量的值。
答案 2 :(得分:0)
这是可以预期的,因为ActiveRecord是设计使然的。如果需要设置任意属性,则必须使用其他类型的对象。
例如,Ruby提供了一个名为
的库OpenStruct
允许您创建可以在其中分配任意键和值的对象。如果您想从属性中获取没有自我的价值,它将为您提供类OpenStruct的实例,该实例具有实例全局变量attribute。但是,如果要设置新属性,它将使用新属性创建类OpenStruct的新实例。没有自我,您将拥有一个旧的OpenStruct对象,该对象没有属性,并且会给您错误。
您可能要使用这样的库,然后仅在需要保存到数据库时才将其转换为相应的ActiveRecord实例。
不要尝试将ActiveRecord建模为您刚才描述的行为,因为它根本不是设计为以这种方式行为