Rails范围与当前用户一起查找

我正在使用Rails 3和Devise进行用户身份validation。 假设我有一个User模型,启用了Devise,还有一个Product模型,以及一个User has_many Products。

在我的Products控制器中,我希望我的find方法由current_user限定,即。

@product = current_user.products.find(params[:id])

除非用户是管理员用户,即current_user.admin?

现在,我几乎在每个方法中运行该代码,这看起来很乱:

 if current_user.admin? @product = Product.find(params[:id]) else @product = current_user.products.find(params[:id]) end 

这样做有更优雅/标准的方式吗?

如果你在很多控制器中运行这个代码,你应该把它变成一个beforefilter,并定义一个方法来在你的ApplicationController中做到这一点:

 before_filter :set_product, :except => [:destroy, :index] def set_product @product = current_user.admin? ? Product.find(params[:id]) : current_user.products.find(params[:id]) end 

我不知道你用什么来确定用户是否是管理员(角色),但是如果你看看CanCan ,它有一个access_by范围接受一种能力(一个控制用户可以和不能用户的对象) do)并根据您自己编写的权限返回用户有权访问的记录。 这可能真的是你想要的,但是剥离你的权限系统并替换它对你来说可能是可行的,也可能是不可行的。

我喜欢这样做:

 class Product scope :by_user, lambda { |user| where(:owner_id => user.id) unless user.admin? } end 

这允许您在控制器中编写以下内容:

 Product.by_user(current_user).find(params[:id]) 

您可以在Product上添加一个类方法,并将用户作为参数发送。

 class Product < ActiveRecord::Base ... def self.for_user(user) user.admin? ? where({}) : where(:owner_id => user.id) end 

然后你可以像这样调用它:

 Product.for_user(current_user).find(params[:id]) 

PS:可能有更好的方法去做where({})