为什么解释代码不会影响 Ruby 中的"messages"行为?



我在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.statusnil

最新更新