在研究了 DHH 和其他关于基于键的缓存过期和俄罗斯娃娃缓存的博客文章之后,我仍然不确定如何处理一种关系类型。具体来说,是一种has_many
关系。
我将在示例应用程序上分享我的研究结果。这是一个小故事,所以请稍等。假设我们有以下 ActiveRecord 模型。我们只关心模型的适当更改cache_key
,对吗?
class Article < ActiveRecord::Base
attr_accessible :author_id, :body, :title
has_many :comments
belongs_to :author
end
class Comment < ActiveRecord::Base
attr_accessible :article_id, :author_id, :body
belongs_to :author
belongs_to :article, touch: true
end
class Author < ActiveRecord::Base
attr_accessible :name
has_many :articles
has_many :comments
end
我们已经有一篇文章,有一条评论。两者都出自不同的作者。目标是cache_key
在以下情况下对文章进行更改:
- 文章的正文或标题更改
- 其评论的正文发生了变化
- 文章作者姓名变更
- 文章评论作者姓名变更
所以默认情况下,我们适用于案例 1 和 2。
1.9.3-p194 :034 > article.cache_key
=> "articles/1-20130412185804"
1.9.3-p194 :035 > article.comments.first.update_attribute('body', 'First Post!')
1.9.3-p194 :038 > article.cache_key
=> "articles/1-20130412185913"
但不适用于案例 3。
1.9.3-p194 :040 > article.author.update_attribute('name', 'Adam A.')
1.9.3-p194 :041 > article.cache_key
=> "articles/1-20130412185913"
让我们cache_key
为Article
.
class Article < ActiveRecord::Base
attr_accessible :author_id, :body, :title
has_many :comments
belongs_to :author
def cache_key
[super, author.cache_key].join('/')
end
end
1.9.3-p194 :007 > article.cache_key
=> "articles/1-20130412185913/authors/1-20130412190438"
1.9.3-p194 :008 > article.author.update_attribute('name', 'Adam B.')
1.9.3-p194 :009 > article.cache_key
=> "articles/1-20130412185913/authors/1-20130412190849"
赢!但这当然不适用于案例 4。
1.9.3-p194 :012 > article.comments.first.author.update_attribute('name', 'Bernard A.')
1.9.3-p194 :013 > article.cache_key
=> "articles/1-20130412185913/authors/1-20130412190849"
那么还有哪些选择呢?我们可以对 上的has_many
关联做一些事情Author
,但has_many
没有{touch: true}
选择,可能是有原因的。我想它可以按照以下方式实现。
class Author < ActiveRecord::Base
attr_accessible :name
has_many :articles
has_many :comments
before_save do
articles.each { |record| record.touch }
comments.each { |record| record.touch }
end
end
article.comments.first.author.update_attribute('name', 'Bernard B.')
article.cache_key
=> "articles/1-20130412192036"
虽然这确实有效。它通过加载、实例化和更新每篇文章和另一篇文章的评论,对性能产生巨大影响。我不相信这是一个正确的解决方案,但什么是?
当然 37signals 用例/示例可能会有所不同:project -> todolist -> todo
. 但我想象一个单一的待办事项也属于用户。
如何解决这个缓存问题?