【问题标题】:Does Rails have tags for expiring a cache?Rails 是否有过期缓存的标签?
【发布时间】:2011-08-05 15:04:43
【问题描述】:

我们的应用在控制器中使用Rails.cache 来缓存视图范围之外的一些项目(如元标记),然后在大部分视图上使用fragment_caching。

视图缓存了一个主模型,但我们在该主缓存中使用了来自 5 个其他模型(未通过关联连接)的数据。使用主模型上的清扫器很容易使片段过期,但那些附加模型也会发生变化,需要触发此页面过期。

我们不能使用正则表达式路由来删除缓存键,因为我们只能通过主模型引用这个缓存条目——其他模型由我们在控制器的缓存块内执行的昂贵查询确定.

Rails 3 是否有办法本质上使用 tags 来标记缓存条目,所以当页面上的 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

我的目标:

  • 我:“哦,页面@cache_key 已更改,让我们将其过期!”
  • Rails: Okay, easy!
  • 我:“其中一个相似的页面改变了他们的第一张照片,我该怎么办?”
  • 导轨: Umm... #(*$^*@ .. does ... not ... compute.

【问题讨论】:

  • 一些缓存系统比其他系统有更多的功能。您打算使用哪个?
  • 我还没有找到一个支持类似标签的系统。内置缓存 cache_fu 和 cache_money 都不支持类似标签的系统。
  • 你有没有想过创建一个观察者来为你管理这个?
  • 我遇到了与 Sweeper 相同的问题——我需要通过一个键访问缓存的项目,但我需要能够通过 6 个“短语”中的任何一个使其过期。我会在问题中解释。
  • 也意味着没有一个可用的缓存存储,如 filestore 或 memcached 似乎支持这个概念。

标签: ruby-on-rails caching tags


【解决方案1】:

正如 tadman 在问题的 cmets 中所说,我必须发明自己的解决方案,因为 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

从技术上讲,我可以在Pages 上建立一个自我引用的has_many 关系,但我决定不这样做,因为我不需要那样引用它。我刚刚创建了一个简单的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

【讨论】:

    【解决方案2】:

    这个视频http://railslab.newrelic.com/2009/02/19/episode-8-memcached很好地解释了 Rails 如何为内容过期生成标签

    如果你将整个对象传递到缓存中,它会生成一个缓存键,该键使用时间戳,当你更改对象时会更新。

    【讨论】:

    • 请注意,上面的视频是针对 memcached 的,但 cahche 密钥生成并不特定于此
    【解决方案3】:

    收银员可能会有所帮助。 “基于标签的缓存”

    # in your view
    cache @some_record, :tag => 'some-component'
    
    # later
    Cashier.expire 'some-component'
    

    https://github.com/twinturbo/cashier

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-09
      • 1970-01-01
      • 2012-03-30
      • 2015-11-19
      • 2011-02-28
      • 1970-01-01
      • 1970-01-01
      • 2013-01-02
      相关资源
      最近更新 更多