不使用self而从模型设置属性不起作用

时间:2011-03-20 15:23:05

标签: ruby-on-rails ruby naming-conventions self

设备型号具有以下属性: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”属性。

有些人告诉我,避免在课堂方法中使用“自我”是一种好方法。 但这会带来麻烦。

问题是 - 为什么不使用“自我”就行不通?

3 个答案:

答案 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,它将返回局部变量的值。

previous question

更好地解释了这一点

答案 2 :(得分:0)

这是可以预期的,因为ActiveRecord是设计使然的。如果需要设置任意属性,则必须使用其他类型的对象。

例如,Ruby提供了一个名为

的库
  

OpenStruct

允许您创建可以在其中分配任意键和值的对象。如果您想从属性中获取没有自我的价值,它将为您提供类OpenStruct的实例,该实例具有实例全局变量attribute。但是,如果要设置新属性,它将使用新属性创建类OpenStruct的新实例。没有自我,您将拥有一个旧的OpenStruct对象,该对象没有属性,并且会给您错误。

您可能要使用这样的库,然后仅在需要保存到数据库时才将其转换为相应的ActiveRecord实例。

不要尝试将ActiveRecord建模为您刚才描述的行为,因为它根本不是设计为以这种方式行为