2

是否有任何内置方法可以将实例变量附加到记录?例如,假设我有一个Userfoo attr_accessor

class User < ActiveRecord::Base
  ...
  attr_accessor :foo
end

如果我做

u = User.first
u.foo = "bar"
u.foo # -> "bar"
User.find(1).foo # => nil

这是正确的行为,我理解为什么:实例变量存在于实例(在内存中)而不是记录。我想要的是类似于记录变量的东西,因此在上面的示例中u.foo在我的应用程序的同一实例中User.find(1).foo返回相同的值。我不想要持久性:它不适合成为表中的一列,它只适合在控制器操作、控制台会话等的生命周期中为同一记录返回相同的值。也不我想要一个类变量 via ,因为没有理由应该与.foofoocattr_accessorUser.find(1).fooUser.find(2).foo

我能想到的最好的办法是用类变量数组和实例方法来伪造它来获取/设置数组的适当元素:

class User < ActiveRecord::Base

  cattr_accessor :all_the_foos
  self.all_the_foos = Array.new

  def foo
    self.all_the_foos[id]
  end

  def foo= new_foo
    self.all_the_foos[id] = new_foo
  end

end

这几乎可以工作,但它不适用于未保存的记录,例如User.new.foo = "bar"失败。

4

2 回答 2

2

您可以使用Thread.current来设置在控制器操作调用的上下文中处于活动状态的变量。您当前的实现不保证在调用之间重置上下文。

class User < ActiveRecord::Base

  after_create    :set_thread_var

  def foo
    new_record? ? @foo : Thread.current["User-foo-#{id}"]
  end

  def foo=(val)
    new_record? ? (@foo = val) : (Thread.current["User-foo-#{id}"] = val)
  end

private

  def set_thread_var
    Thread.current["User-foo-#{id}"] = @foo if defined?(@foo)
  end

end
于 2011-10-21T18:37:23.023 回答
1

我想不出比您的类变量解决方案更好的主意。为了解决您的“ new”问题,我会使用after_initialize.

class User < ActiveRecord::Base
  after_initialize :init_foos

  cattr_accessor :all_the_foos

  def foo
    self.all_the_foos[id]
  end

  def foo= new_foo
    self.all_the_foos[id] = new_foo
  end

  private
  def init_foos
    @@all_the_foos ||= []
  end
end
于 2011-10-21T17:39:29.017 回答