6

我是一个尝试为我的应用程序实现缓存的 Rails 新手。我安装了 memcached 并将其配置在我的 development.rb 中,如下所示:

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 第一次,rails 击中我的控制器并缓存产品操作。

2)我以用户 B 的身份注销并登录,它仍然以用户 A 的身份登录,并显示用户 A 而不是用户 B 的产品。它甚至没有击中我的控制器。

关键可能是路由,在我的 memcached 控制台中,我看到它是基于相同的键获取的。

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

动作缓存不是我应该使用的吗?我将如何缓存和显示用户特定的产品?

谢谢你的帮助。

4

2 回答 2

15

第一个问题是你的 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

这应该可以帮助您为每个用户使用单独的缓存。

于 2011-02-23T22:07:05.237 回答
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
于 2011-04-11T01:19:08.220 回答