2016-09-27 53 views
0

我在ActiveRecord模型中有一个验证器,其中我遇到了一些真的很奇怪的行为。为什么解释的代码不能影响Ruby中的“消息”行为?

例子:

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不知何故被设置好的为零。 当我改变statusself.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 

有人能解释一下吗?怎么不解释的代码可以从方法消息“重定向”给一个变量?可以吗?

+1

如果my_conditions_1是真的,你只能给'status'分配一些东西。那么,如果'my_conditions_1'是假的,会发生什么?那么'status'是未初始化的,未初始化的局部变量的计算结果为'nil',就像实例变量一样。 –

+0

@JörgWMittag那么如何在第一次分配前正确打印出来? –

+0

因为它在第一次赋值之前不存在,因此被解释为方法调用,并且可能该方法返回某个值。 –

回答

3

要访问对象的属性可以用attribute来做到这一点。

在更新这个属性应该使用self.attribute,否则应该如何Rails的知道你的意思来设置它的属性,而不是定义局部变量?

经验法则:用self分配属性,不使用它来读取属性。

编辑

关于你提到的更新:

由于@约尔格W¯¯米塔格说(谁也说好?):

好,status是未初始化,UND未初始化的局部变量 评估为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知道确切的,你的意思。

+0

那么,你实际上只需要'自我'分配任务。 :) –

+0

@SergioTulentsev我的语法今天很蹩脚,thx编辑!我的意思是分配,实际上你可以使用'destroy','update'等,而不用明确的'self'。 –

+0

或访问与局部变量同名的方法。 – Stefan

2

如果要更新的属性,则必须使用self

self.status = 'something' 

否则轨将承担作为一个局部变量所以

puts self.status 
#=> "something" 

status = 'abc' 

puts self.status 
#=> "something" 

self.status = 'something else' 
puts self.status 
#=> "something else" 

状态,但你可以只用status访问属性。

为什么status被设置为零?

也许这行

status = status_was 

前status_changed因?也许self.statusnil

+0

没有局部变量。 你是对的,但你的回答并不能解释为什么在**失败**条件'状态'之前为什么是正确的并且在它迷路了之后。 –

+0

检查更新的答案 –

+0

而且你没有回答我的问题。好吧,我知道了,'status'是局部变量,但为什么它被设置为'nil'? –

相关问题