Кеширование в 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 и переполнения стека!