我在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
有人能解释一下吗?不解释的代码如何"重定向"消息从方法到变量?可以吗? 要访问对象的属性,可以使用attribute
。
当更新这个属性应该使用self.attribute
,因为否则Rails怎么知道你的意思是设置它的属性,而不是定义本地变量?
经验法则:使用self
来分配属性,不要使用它来读取属性。
关于你的更新:
正如@Jörg W Mittag所说(谁会说得更好?):
好吧,
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准确地知道是什么意思。
标题>如果你正在更新属性,那么你必须使用self
self.status = 'something'
否则rails将假定status为一个局部变量,因此
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