我们的应用程序在控制器中使用Rails.cache
来缓存视图范围之外的一些项目(如元标记),然后在视图的大部分上使用fragment_caching。
视图缓存一个主模型,但我们在主缓存中使用了来自 5个其他模型(未通过关联连接)的数据。在主模型上使用清扫程序很容易使片段过期,但这些附加模型也会更改并需要触发此页面过期。
我们不能使用正则表达式路由来删除缓存键,因为我们必须仅通过主模型引用此缓存条目 - 其他模型由我们在控制器的缓存块内执行的昂贵查询确定
Rails 3是否有办法基本上使用标记来标记缓存条目,因此当页面上的6个模型中的任何一个更改时我们可以删除它,但我们仍然可以找到缓存条目仅从主模型的钥匙?
这里有一些虚拟代码来表达这个想法:
在控制器中
@cache_key = "/page/#{params[:name]}/#{params[:id]}"
unless fragment_exist? ( { :slug => @cache_key })
# run our processes here that will be needed in the view,
# then cache the data that is used outside the view
Rails.cache.write(@cache_key, { (data goes here) } )
# run our expensive query here:
@similar_pages = Page.pricey_query!.limit(5).all
else
cached = Rails.cache.read(@cache_key)
end
在视图中
- cache( {:slug => @cache_key} ) do
- @similar_pages.each do |page|
= image_tag page.photos.first.image.url
-# more pretty stuff here
我的目标:
Okay, easy!
Umm... #(*$^*@ .. does ... not ... compute.
答案 0 :(得分:2)
正如tadman在问题的评论中所述,我必须发明自己的解决方案,因为Rails在技术上并不允许我需要它们的标签。对于那些有兴趣做类似事情的人来说,这是一个通用的解决方案:
我创建了一个名为SimilarPages
的新表:
create_table :similar_pages, {:id => false} do |t|
t.integer :page_id, :similar_page_id
# you could also do `t.string :tag_name` or similar
end
add_index :similar_pages, :page_id
add_index :similar_pages, :similar_page_id
从技术上讲,我可以在has_many
上做一个自我引用的Pages
关系,但我决定不这样做,因为我不需要那样引用它。我刚刚创建了一个简单的SimilarPage
模型:
class SimilarPage < ActiveRecord::Base
belongs_to :page
belongs_to :similar_page, :class_name => 'Page'
end
然后使用ar-extensions
(因为我很懒,也因为我想在一个INSERT语句中执行此操作),我在缓存块中执行此操作:
SimilarPage.delete_all("page_id = '#{@page_id}'")
SimilarPage.import [:page_id, :similar_page_id], @similar_pages.collect {|s| SimilarPage.new(:page_id=>@page_id,:similar_page_id=>s.id)}
在我观察员的expire_cache_for
方法中,我这样做:
SimilarPage.where(:similar_page_id => expiring_page.id).all.each do |s|
ActionController::Base.new.expire_fragment(/page_show__#{s.page_id}__.*/)
# the regexp is for different currencies being cached ^
Rails.cache.delete("page_show_#{s.page_id}")
end
答案 1 :(得分:0)
在此视频中,Rails如何为内容过期生成标记有一个很好的解释http://railslab.newrelic.com/2009/02/19/episode-8-memcached
如果将整个对象传递到缓存中,它将生成一个缓存键,该缓存键使用时间戳,当您更改对象时,该时间戳将更新。
答案 2 :(得分:0)
收银员可能会有所帮助。 “基于标记的缓存”
# in your view
cache @some_record, :tag => 'some-component'
# later
Cashier.expire 'some-component'