2011-02-23 55 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