2011-02-23 90 views
6

我是一名試圖爲我的應用實施緩存的Rails新手。 我安裝了Memcached和我development.rb其配置如下:Rails針對用戶特定記錄的動作緩存

config.action_controller.perform_caching    = true 
config.cache_store = :mem_cache_store 

我有一個控制器的ProductsController,顯示用戶的特定產品,當他們在登錄

class ProductsController < ApplicationController 
    caches_action :index, :layout => false 
    before_filter :require_user 

    def index 
    @user.products    
    end 
end 

The route for index action is: /products 

的問題是,當我以

登錄:1)用戶A第一次使用軌道撞擊我的控制器並緩存產品動作。

2)我註銷並登錄爲用戶B,它仍然會記錄我作爲用戶A和顯示產品,爲用戶A和用戶無法B. 它甚至不打我的控制器。

關鍵可能是路由,在我的memcached控制檯中,我發現它是基於相同的密鑰提取的。

20 get views/localhost:3000/products 
20 sending key views/localhost:3000/products 

行動緩存不是我應該使用的嗎?我將如何緩存和顯示用戶特定的產品?

感謝您的幫助。

回答

14

第一個問題是您的before_filter for require_user是在操作緩存之後,所以不會運行。爲了解決這個問題,使用該控制器代碼:

class ProductsController < ApplicationController 
    before_filter :require_user 
    caches_action :index, :layout => false 

    def index 
    @products = @user.products    
    end 
end 

其次,動作緩存你正在做同樣的事情的頁面緩存,但過濾器運行後,讓你的@ user.products代碼將無法運行。有幾種方法可以解決這個問題。

首先,如果您希望可以根據傳遞給頁面的參數來緩存操作。例如,如果你傳遞一個USER_ID參數,你可以緩存基於該參數是這樣的:

caches_action :index, :layout => false, :cache_path => Proc.new { |c| c.params[:user_id] } 

其次,如果你想簡單緩存查詢,而不是整個頁面,你應該完全刪除動作緩存和只緩存查詢,如下所示:

def index 
    @products = Rails.cache.fetch("products/#{@user.id}"){ @user.products } 
end 

這應該有助於您逐步爲每個用戶分配一個緩存。

+0

感謝潘。我最後提出了使用查詢緩存的建議。任何有關如何在列表中的某個產品的某個屬性得到更新時不會完全使「products/{#user.id}」的整個緩存無效的想法... like product(10).price? – truthSeekr 2011-02-23 23:45:05

+1

如果需要,可以緩存單個產品而不是全部緩存值,以便可以更好地控制哪些緩存值失效。儘管如此,這是一把雙刃劍 - 您希望使緩存失效的程度越高,獲得的越複雜,需要製作的單個緩存語句也越多。我建議簡單地使整個產品列表緩存無效,這可能是最簡單的做法。如果您從這種方法開始遇到性能問題,那麼嘗試進一步深入並創建更詳細的緩存。不要過度優化。 – 2011-02-24 00:00:50

+0

非常感謝您的幫助和建議。 – truthSeekr 2011-02-24 00:14:54

0

基於Pan Thomakos的回答,如果您從處理身份驗證的控制器繼承,則需要從父類複製before_filter。例如:

class ApplicationController < ActionController::Base 
    before_filter :authenticate 
end 

class ProductsController < ApplicationController 
    # must be here despite inheriting from ApplicationController 
    before_filter :authenticate 
    caches_action :index, :layout => false 
end