[英]Rails 3 caching: How do I use a sweeper with Action and Fragment caching to expire the cache?
I'm working on a page that displays a restaurant menu. 我正在处理显示餐厅菜单的页面。 I have 2 models: FoodMenu has_many :products and Product belongs_to :food_menu.
我有2个模型:FoodMenu has_many:products和Product属于to:food_menu。 I don't have controllers for either model.
我没有任何一个模型的控制器。 Instead, I am using a "pages_controller.rb" to display each FoodMenu and its Products with a "menus" action:
相反,我使用“ pages_controller.rb”来显示每个带有“菜单”操作的FoodMenu及其产品:
def menus
@food_menus = FoodMenu.includes(:products).all
end
I want to use Action Caching for the menus page (localhost:3000/menus), which is working, but I can't get the cache to expire when I update, create, or destroy a product. 我想对菜单页面(localhost:3000 / menus)使用“动作缓存”,该菜单页面正在运行,但是当我更新,创建或销毁产品时,缓存无法过期。
At the top of "pages_controller.rb", I have: 在“ pages_controller.rb”的顶部,我有:
caches_action :menus
cache_sweeper :pages_sweeper
I tried creating separate sweepers for the Product and FoodMenu models in app/sweepers using the example code here: http://guides.rubyonrails.org/caching_with_rails.html#sweepers , but that didn't work. 我尝试使用以下示例代码在app / sweepers中为Product和FoodMenu模型创建单独的清扫程序: http ://guides.rubyonrails.org/caching_with_rails.html#sweepers,但这没有用。 Then, I read in a SO entry that the sweeper is supposed to observe all the models that the controller uses, so I assumed that meant I have to create a "pages_sweeper.rb" that observes both the Product and FoodMenu models and expires the "menus" action.
然后,我读了一个SO条目,认为清扫程序应观察控制器使用的所有模型,因此我认为这意味着我必须创建一个“ pages_sweeper.rb”,以观察Product和FoodMenu模型,并使“菜单”操作。 That didn't work either.
那也不起作用。 What am I doing wrong?
我究竟做错了什么? Here is what I have right now in "pages_sweeper.rb":
这是我现在在“ 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
I finally figured it out! 我终于想通了! I was able to get both fragment and action caching to work.
我能够同时使用片段缓存和动作缓存。 From the server logs, it seems that Action Caching is a lot faster, so that's what I'm deploying with.
从服务器日志来看,动作缓存似乎要快得多,所以这就是我要部署的内容。
For Fragment Caching, I created a "food_menu_sweeper.rb" that observes both FoodMenu and Product and expires the fragment that I created in the partial, like so: 对于片段缓存,我创建了一个“ 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
Here is the fragment in the partial: 以下是部分片段:
<% cache("menu items") do %>
<% for food_menu in FoodMenu.full_list %>
...
<% end %>
<% end %>
FoodMenu.full_list is called within the fragment to cache the database query as well, which is defined in the food_menu.rb model: 在片段内调用FoodMenu.full_list来缓存数据库查询,该查询在food_menu.rb模型中定义:
def self.full_list
FoodMenu.includes(:products).all
end
Then, the key here is to place the cache_sweeper in "application_controller.rb"! 然后,这里的关键是将cache_sweeper放在“ application_controller.rb”中! This crucial hint came from reading this SO entry: Rails - fragment cache not expiring
这个关键提示来自阅读以下SO条目: Rails-片段缓存未到期
cache_sweeper :food_menu_sweeper
This all works like a charm. 这一切都像一个魅力。 When I refresh the page, the fragment is read from cache and no database calls are made.
当我刷新页面时,将从高速缓存中读取该片段,并且不会进行数据库调用。 Once I update a product or a food_menu, the cache is cleared and the new data appears and is then cached.
更新产品或food_menu后,将清除缓存并显示新数据,然后将其缓存。
For Action Caching, I added: 对于动作缓存,我添加了:
caches_action :menus
in my "pages_controller.rb", then removed the fragment cache from the partial, and replaced 在我的“ pages_controller.rb”中,然后从部分缓存中删除了片段缓存,并替换了
expire_fragment("menu items")
in food_menu_sweeper.rb, with: 在food_menu_sweeper.rb中,带有:
expire_action(:controller => '/pages', :action => 'menus')
The key here was the leading slash before "pages", which I found via this SO entry: rails caching: expire_action in another namespace 这里的关键是“页面”之前的斜杠,我通过此SO条目找到了它: 轨道缓存:另一个名称空间中的expire_action
Without the leading slash, I was getting a "Can't convert symbol into integer" error when updating items via the ActiveAdmin interface. 没有前导斜线,通过ActiveAdmin界面更新项目时出现“无法将符号转换为整数”错误。
Yay for determination, Google, and Stack Overflow! 是的,决心,谷歌和堆栈溢出!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.