2

レストランのメニューを表示するページに取り組んでいます。私は 2 つのモデルを持っています: FoodMenu has_many :products と Product belongs_to :food_menu です。どちらのモデルのコントローラーも持っていません。代わりに、「pages_controller.rb」を使用して、各 FoodMenu とその製品を「menu」アクションで表示しています。

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

メニュー ページ (localhost:3000/menus) でアクション キャッシュを使用したいのですが、これは機能していますが、製品を更新、作成、または破棄するときにキャッシュを期限切れにすることができません。

「pages_controller.rb」の上部には、次のものがあります。

caches_action :menus
cache_sweeper :pages_sweeper

http://guides.rubyonrails.org/caching_with_rails.html#sweepersのサンプル コードを使用して、 app/sweepers に Product モデルと FoodMenu モデルの個別のスイーパーを作成しようとしましたが、うまくいきませんでした。次に、コントローラーが使用するすべてのモデルをスイーパーが監視することになっている SO エントリを読み込んだので、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

私はついにそれを理解しました!フラグメント キャッシングとアクション キャッシングの両方を機能させることができました。サーバー ログから、アクション キャッシュの方がはるかに高速であるように思われるので、それを使用してデプロイしています。

Fragment Caching のために、FoodMenu と Product の両方を監視し、パーシャルで作成したフラグメントを次のように期限切れにする「food_menu_sweeper.rb」を作成しました。

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')

ここで重要なのは、「ページ」の前の先頭のスラッシュでした。これは、次の SO エントリで見つけました: rails caching: expire_action in another namespace

先頭のスラッシュがないと、ActiveAdmin インターフェイス経由でアイテムを更新するときに、「シンボルを整数に変換できません」というエラーが発生しました。

決意、Google、そしてスタック オーバーフローのためにイェーイ!

于 2012-01-03T21:43:33.400 に答える