Rails 3缓存:如何使用带有Action和Fragment缓存的清理程序使缓存失效?

时间:2012-01-02 04:06:05

标签: ruby-on-rails caching fragment-caching sweeper action-caching

我正在制作一个显示餐馆菜单的页面。我有2个型号:FoodMenu has_many:产品和产品belongs_to:food_menu。我没有这两种型号的控制器。相反,我使用“pages_controller.rb”来显示每个FoodMenu及其产品的“菜单”操作:

def menus
 @food_menus = FoodMenu.includes(:products).all
end

我想在菜单页面(localhost:3000 /菜单)中使用Action Caching,这是有效的,但是当我更新,创建或销毁产品时,我无法使缓存过期。

在“pages_controller.rb”的顶部,我有:

caches_action :menus
cache_sweeper :pages_sweeper

我尝试使用此处的示例代码为app / sweepers中的Product和FoodMenu模型创建单独的清扫器:http://guides.rubyonrails.org/caching_with_rails.html#sweepers,但这不起作用。然后,我在SO条目中读到清扫器应该观察控制器使用的所有模型,所以我认为这意味着我必须创建一个“pages_sweeper.rb” 观察Product和FoodMenu模型并使“菜单”操作过期。那也行不通。我究竟做错了什么?以下是我现在在“pages_sweeper.rb”中的内容:

class PagesSweeper < ActionController::Caching::Sweeper
 observe Product, FoodMenu 

 # If our sweeper detects that a Product was created call this
 def after_create(product)
  expire_cache_for(product)
 end

 # If our sweeper detects that a Product was updated call this
 def after_update(product)
  expire_cache_for(product)
 end

 # If our sweeper detects that a Product was deleted call this
 def after_destroy(product)
   expire_cache_for(product)
 end

 def after_create(food_menu)
  expire_cache_for(food_menu)
 end

 # If our sweeper detects that a FoodMenu was updated call this
 def after_update(food_menu)
   expire_cache_for(food_menu)
 end

 # If our sweeper detects that a FoodMenu was deleted call this
 def after_destroy(food_menu)
   expire_cache_for(food_menu)
 end


 private
 def expire_cache_for(product)
 # Expire the menus action now that we added a new product
 expire_action(:controller => 'pages', :action => 'menus')

 # Expire a fragment
 expire_fragment('all_available_products')
 end

 def expire_cache_for(food_menu)
 # Expire the menus page now that we added a new FoodMenu
 expire_action(:controller => 'pages', :action => 'menus')

 # Expire a fragment
 expire_fragment('all_available_food_menus')
 end
end     

1 个答案:

答案 0 :(得分:0)

我终于明白了!我能够让片段和动作缓存都能正常工作。从服务器日志来看,Action Caching似乎要快得多,因此我正在部署它。

对于片段缓存,我创建了一个&#34; food_menu_sweeper.rb&#34;它会观察FoodMenu和Product,并使我在partial中创建的片段过期,如下所示:

class FoodMenuSweeper < ActionController::Caching::Sweeper
 observe FoodMenu, Product

 def after_save(food_menu)
   expire_cache(food_menu)
 end

 def after_destroy(food_menu)
   expire_cache(food_menu)
 end

 def after_save(product)
   expire_cache(product)
 end

 def after_destroy(product)
   expire_cache(product)
 end

 private

 def expire_cache(food_menu)
  expire_fragment("menu items")
 end

 def expire_cache(product)
  expire_fragment("menu items")
 end

end

以下是部分中的片段:

<% cache("menu items") do %>
  <% for food_menu in FoodMenu.full_list %> 
    ...
<% end %>
<% end %>

在片段内调用FoodMenu.full_list来缓存数据库查询,这在food_menu.rb模型中定义:

def self.full_list
  FoodMenu.includes(:products).all
end

然后,这里的关键是将cache_sweeper放在&#34; application_controller.rb&#34;!这一重要提示来自阅读此SO条目:Rails - fragment cache not expiring

 cache_sweeper :food_menu_sweeper

这一切都像一个魅力。刷新页面时,将从缓存中读取片段,并且不会进行数据库调用。更新产品或food_menu后,将清除缓存并显示新数据,然后缓存。

对于Action Caching,我补充道:

caches_action :menus

在我的&#34; pages_controller.rb&#34;中,然后从部分中删除了片段缓存,并替换了

expire_fragment("menu items")
food_menu_sweeper.rb中的

,附:

expire_action(:controller => '/pages', :action => 'menus')

这里的关键是&#34; pages&#34;之前的主要斜线,我通过这个SO条目找到了:rails caching: expire_action in another namespace

如果没有前导斜线,我就会得到一个&#34;无法将符号转换为整数&#34;通过ActiveAdmin界面更新项目时出错。

Yay for determination,Google和Stack Overflow!