【问题标题】:Rails instance variable for record用于记录的 Rails 实例变量
【发布时间】:2011-12-12 16:44:37
【问题描述】:

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

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

如果我这样做

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

这是正确的行为,我理解为什么:实例变量存在于 instance (在内存中)而不是记录。我想要的是类似于 record 变量的东西,因此在上面的示例中,u.fooUser.find(1).foo 在我的应用程序的同一实例中返回相同的值。我不想要持久性:foo 不适合作为表中的一列,foo 在例如控制器操作、控制台的生命周期内为同一记录返回相同的值是合适的session 等。我也不希望通过 cattr_accessor 获得类变量,因为没有理由 User.find(1).foo 应该与 User.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" 失败。

【问题讨论】:

  • 我想在不知道你想要存储什么样的值的情况下很难回答这个问题。您说您“不想要持久性”,但听起来您希望实例从一个请求/会话/周到下一个保持相同的值,这正是“持久性”的定义。你能告诉我们更多你在这里追求什么的线索吗?
  • 该值将是另一个类的实例。我希望在常规实例变量和类变量之间保持一段时间。因此,例如,如果我从控制器动作触发了一系列动作,则该值将是一致的,但在动作完成后它不需要保留其值。它不是控制器变量,这只是一个示例。我宁愿不讨论上下文 b/c 的细节,因为它相对复杂。我非常确信我提出的问题正是我需要知道的。

标签: ruby-on-rails ruby instance-variables class-variables


【解决方案1】:

您可以使用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

【讨论】:

  • +1,谢谢。不过,我不得不放弃attr_accessor,否则我的foofoo= 方法将被忽略。我需要阅读Thread.current 才能真正了解生命周期是什么,但这正好解决了我的问题。
【解决方案2】:

我想不出比您的类变量解决方案更好的主意。为了解决您的“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

【讨论】:

  • +1,谢谢。我选择了@KandadaBoggu 的解决方案,因为它是明确的线程安全的,并且当您访问 User.last.foo 时它不会创建长度为 N 的数组(这是我的错)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多