2

在我当前的 Rails 应用程序中,我将大量数据从数据库中提取到内存中,以便我可以启动一个长时间运行的后台任务,我不想每 5 秒访问一次数据库。

这一切都很好,但我有一些不雅的代码,如果可能的话,我想去掉它们。

例如,我有一个用户模型,并且用户模型可以以联系人的形式链接到其他用户模型,而联系人又可以链接回第一个用户模型,依此类推。建模如下(感谢 Milan Novota 早期的帮助):-

class User < ActiveRecord::Base
  has_many :contact_records, :foreign_key => :owner_id
  has_many :contacts, :through => :contact_records, :class_name => "User"
end

class ContactRecord < ActiveRecord::Base
  belongs_to :owner, :class_name => "User"
  belongs_to :user
end

所以现在我可以输入

user_a_contacts = user_a.contact_records
=> [user_b, user_c]

并获取用户 a 的所有联系人。现在假设我想通过用户 a 获取用户 b 的联系人(想不出我为什么会这样做,但这只是一个例子!)

user_b_contacts = user_a_contacts.first.contact_records
=> [user_a, user_c]

现在我可以得到用户 a 的名字(以一种复杂的、迂回的、从未在现实世界中使用的方式)

user_a_name = user_b_contacts.first.name
=> "Jamie"

到目前为止,一切都很好。现在我更改用户 a 的名称

user_a.name = "Sandy"
=> "Sandy"

如果像以前一样从数据库中再次访问用户 a 的名称,我会得到

user_a_name = user_b_contacts.first.name
=> "Sandy"

但是,如果我渴望加载并将这个值保存在内存中,我会得到

user_a_name = user_b_contacts.first.name
=> "Jamie"

但执行以下操作给了我正确的答案

user_a.name
=> "Sandy"

很明显,预加载为原始用户和从 ContactRecord 对象预加载的用户创建不同的用户对象。

所以(最后!)我的问题是:-

目前,我已经通过使用来解决这个问题

@users.each.detect{|user| user == user_b_contacts.first}

(其中@users 是预先加载的用户对象列表)。有没有办法可以更新预先加载的用户对象?

请注意: -

a)我正在使用以下内容进行急切加载

User.find(:all, :include => [ {:contact_records => :contacts] } ])

b) 显然这不是我正在使用的实际代码,但为了显示该代码,会有更多的解释和说明,我想我已经让你厌烦了!相信我,我使用的真实示例确实需要这种结构才能正常工作,尽管看起来很奇怪!;)

c) 我可能在重构示例时引入了拼写错误和错误,但请忽略这些。我只需要知道是否可以在不访问数据库的情况下重新加载热切的用户。

提前谢谢了!

更新:如下所述,模型数据在流程运行结束之前不会保存到数据库中,因此重新加载将不起作用,因为数据库中的数据不会改变。

4

2 回答 2

4

好的。我将把你的问题浓缩成一个新问题并回答那个问题。如果我误解了,请原谅我,这不是你要问的。

问题

如果user是我contacts提前加载了关联的 ActiveRecord 模型,当关联在数据库中发生更改时User.first(:include => :contacts),如何刷新contacts关联?

回答

您可以通过我知道的两种方式使关联缓存无效。首先你可以这样做:

user.reload

这将从头开始重新加载整个用户模型。一个稍微不那么激烈的方法是这样做

user.clear_association_cache

这不会重新加载所有user,但会清除缓存的关联。

无论哪种方式,下次您这样做user.contacts时都会从数据库中重新加载它们。

于 2009-04-17T11:25:52.357 回答
0

非常感谢您的回复,丹尼尔。虽然你的问题并不完全正确,但你让我意识到我错过了一个关键点!数据库记录不会更新,因为我没有保存!在任何时候。

我正在做的事情的要点是将模型数据提取到实例变量中,以加快后台进程。因此,第一次加载的数据在进程运行结束之前不会保存回数据库。

我希望的是一种方法,您可以在急切加载时指定一列的值与已加载的另一个模型相关。

例如,

User.find(:all, :include => [ {:contact_records => (:contacts as User)] } ])

或类似的。

据我所知,Rails 中没有这样的语法,但是我希望我错了!:)

希望这使它更清楚一点,并再次感谢您的回复。

于 2009-04-17T12:47:58.960 回答