为什么不解释代码会影响Ruby中的“消息”行为?

时间:2016-09-27 13:41:20

标签: ruby-on-rails ruby

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

有人可以解释一下吗?如何解释代码不能将“重定向”消息从方法转换为变量?可以吗?

2 个答案:

答案 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.statusnil