80

问题:我什么时候需要在 Rails 的模型中使用 self?

我的set一个模型中有一个方法。

class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    self.active_flag = val
    self.save!
  end
end

当我这样做时,一切正常。但是,当我这样做时:

class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    active_flag = val
    save!
  end
end

active_flag 值不会改变,而是静默失败。有人可以解释吗?

我找不到任何重复项,但如果有人找到也可以。

4

4 回答 4

76

当您对调用该方法的实例执行操作时,您使用 self.

使用此代码

class SocialData < ActiveRecord::Base
  def set_active_flag(val)
    active_flag = val
    save!
  end
end

您正在定义一个名为 active_flag 的全新作用域局部变量,将其设置为传入的值,它不与任何内容相关联,因此当方法结束时它会立即被丢弃,就像它从未存在一样。

self.active_flag = val

然而,告诉实例修改它自己的名为 active_flag 的属性,而不是一个全新的变量。这就是它起作用的原因。

于 2012-05-29T19:09:25.943 回答
70

这是因为范围界定而发生的。当您在一个方法中并尝试像这样设置一个新变量时:

class SomeData < ActiveRecord::Base
  def set_active_flag(val)
    active_flag = val
  end
end

您正在创建一个位于 set_active_flag 内部的全新变量。一旦执行完毕,它就会消失,不会self.active_flag以任何方式改变(实际的实例变量)。

但是(这对我来说是一个困惑的根源):当您尝试在 ruby​​ 中读取实例变量时,如下所示:

class SomeData < ActiveRecord::Base
  def whats_my_active_flag
    puts active_flag
  end
end

您实际上会self.active_flag返回(实际的实例变量)。


原因如下:

Ruby 将尽其所能避免返回nil.

  1. 它最初询问“是否active_flag存在于whats_my_active_flag?
  2. 它搜索并意识到答案是“nope”,所以它跳一个级别,到 SomeData 的实例
  3. 它再次问同样的事情:“active_flag在这个范围内存在吗?
  4. 答案是“是的”,所以它说“我有东西要给你”,然后它就会返回!

但是,如果您active_flag在 中定义whats_my_active_flag,然后请求它,它会再次执行以下步骤:

  1. 它询问“是否active_flag存在于whats_my_active_flag?
  2. 答案是“是的”,所以它返回那个值

在任何一种情况下,除非您明确告诉它,否则它不会更改的值。self.active_flag

描述这种行为的一个简单方法是“它不想让你失望”并返回nil——所以它尽最大努力找到它可以找到的任何东西。

同时,“它不想弄乱您不打算更改的数据”,因此它不会更改实例变量本身。

希望这可以帮助!

于 2013-12-23T06:31:57.867 回答
2

这是为了确保您使用的是 setter 方法而不是限定新变量的范围。这是一个 Ruby 和 AR 使用细节,经常让人们绊倒(另一个是(错误)使用实例变量)。

请注意,已经有update_attributes!虽然我理解抽象的愿望。

还有切换!,这可能会更好,具体取决于您与标志的接口。

于 2012-05-29T19:10:13.563 回答
0

When use active_flag = val ruby thought your are define a local variable, the best way is self.active_flag = val, if you got it, hope you know that send(:active_flag=, val) will works too.

于 2017-10-30T15:30:51.720 回答