2

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

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

我想对菜单页面 (localhost:3000/menus) 使用动作缓存,它正在工作,但是当我更新、创建或销毁产品时,我无法让缓存过期。

在“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     
4

1 回答 1

0

我终于想通了!我能够同时使用片段和动作缓存。从服务器日志来看,Action Caching 似乎要快得多,所以这就是我正在部署的。

对于片段缓存,我创建了一个“food_menu_sweeper.rb”,它同时观察 FoodMenu 和 Product,并使我在部分中创建的片段过期,如下所示:

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放到“application_controller.rb”中!这个重要的提示来自阅读这个 SO 条目:Rails - fragment cache not expiring

 cache_sweeper :food_menu_sweeper

这一切都像一个魅力。当我刷新页面时,从缓存中读取片段并且不进行数据库调用。一旦我更新了一个产品或一个 food_menu,缓存就会被清除,新数据就会出现,然后被缓存。

对于动作缓存,我添加了:

caches_action :menus

在我的“pages_controller.rb”中,然后从部分中删除片段缓存,并替换

expire_fragment("menu items")

在 food_menu_sweeper.rb 中,带有:

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

这里的关键是“pages”之前的前导斜杠,我通过这个 SO 条目找到了它:rails caching: expire_action in another namespace

如果没有前导斜杠,我在通过 ActiveAdmin 界面更新项目时收到“无法将符号转换为整数”错误。

为决心、谷歌和 Stack Overflow 喝彩!

于 2012-01-03T21:43:33.400 回答