Кеширование в Rails 3: Как использовать очиститель с кэшированием действий и фрагментов для истечения срока действия кэша?

Я работаю над страницей, которая отображает меню ресторана. У меня есть 2 модели: FoodMenu has_many: продукты и продукт принадлежит:food_menu. У меня нет контроллеров ни для одной модели. Вместо этого я использую "pages_controller.rb", чтобы отобразить каждое FoodMenu и его Продукты с действием "меню":

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

Я хочу использовать Action Caching для страницы меню (localhost:3000/menus), которая работает, но у меня не получается истечь срок действия кэша при обновлении, создании или уничтожении продукта.

В верхней части "pages_controller.rb" у меня есть:

caches_action :menus
cache_sweeper :pages_sweeper

Я попытался создать отдельные уборщики для моделей Product и FoodMenu в app/sweepers, используя приведенный ниже пример кода: http://guides.rubyonrails.org/caching_with_rails.html, но это не сработало. Затем я прочитал в записи 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 ответ

Я наконец-то понял! Я смог заставить работать как кеш, так и фрагменты. Судя по логам сервера, кажется, что кэширование действий происходит намного быстрее, поэтому я развернул его.

Для Кэширования фрагментов я создал "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 - фрагментный кэш не истекает

 cache_sweeper :food_menu_sweeper

Это все работает как шарм. Когда я обновляю страницу, фрагмент читается из кеша, и база данных не обращается. Как только я обновляю продукт или food_menu, кеш очищается, появляются новые данные и затем кешируются.

Для Action Caching я добавил:

caches_action :menus

в моем "pages_controller.rb", затем удалил кеш фрагмента из частичного и заменил

expire_fragment("menu items")

в food_menu_sweeper.rb, с:

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

Ключом здесь был начальный слеш перед "страницами", который я нашел с помощью этой записи SO: rails caching: expire_action в другом пространстве имен

Без косой черты я получаю сообщение об ошибке "Не удается преобразовать символ в целое число" при обновлении элементов через интерфейс ActiveAdmin.

Yay для определения, Google и переполнения стека!

Другие вопросы по тегам