我在ActiveRecord模型中有一个验证器,其中我遇到了一些 真正奇怪的 行为。
示例:
if status_changed?
p status # output on line below
# <= "my_status_1"
p my_conditions_1 # output on line below
# <= false
if my_conditions_1
errors.add(:status, 'Error1')
status = status_was
end
p status # output on line below
# <= nil
# my_conditions_2 depends on "status variable"
if my_conditions_2
errors.add(:status, 'Error2')
status = 2
end
end
第二个条件总是失败,因为status
以某种方式被设置为nil。 但是当我将status
更改为self.status
时,一切都按预期开始工作。
已更新
我有规则,如果分配属性我必须使用self
,感谢所有解释它的人。但部分代码的行为对我来说仍然不明显
更一般的例子:
class Detector
def status
"Everything ok"
end
def check
p status
# <= "Everything ok"
if false
status = "Danger!"
end
p status
# <= nil
end
end
detector = Detector.new
detector.check
有人可以解释一下吗?如何解释代码不能将“重定向”消息从方法转换为变量?可以吗?
答案 0 :(得分:3)
要访问对象的属性,可以使用attribute
进行访问。
更新此属性时应该使用self.attribute
,否则Rails应该如何知道你的意思是设置它的属性,而不是定义局部变量?
经验法则:使用self
分配属性,不要用它来读取属性。
关于您的更新:
正如 @JörgWMittag 所说(谁会说更好?):
好吧,
status
是未初始化的,未初始化的局部变量 评估为nil
,就像实例变量一样。
要使您的代码示例按预期运行,您可能希望将status
作为方法调用。看:
class Detector
def status
"Everything ok"
end
def check
p status
# <= "Everything ok"
status = "Danger!" if false
status() # or method(:status).call
# <= "Everything ok"
end
end
第一个p status
有效,因为Ruby会查找局部变量status
。当它找不到它时,它会查找名为status
的方法(通过方法查找)。所以它打印出它"Everything ok"
。
然后在解析if
语句并看到未初始化的本地变量status
。因此,当您引用它时,它是合法的nil
。
换句话说, 让Ruby确切地知道 ,你的意思。
答案 1 :(得分:2)
如果要更新属性,则必须使用self
self.status = 'something'
否则rails会将状态视为局部变量,所以
puts self.status
#=> "something"
status = 'abc'
puts self.status
#=> "something"
self.status = 'something else'
puts self.status
#=> "something else"
但您只需status
即可访问该属性。
为什么
status
设置为nil?
也许是因为这一行
status = status_was
在status_changed之前?也许self.status
是nil