2011-11-18 148 views
16

我使用Rails 3与Devise进行用户身份验证。比方说,我有一个用户模型,启用了Devise,一个产品模型,以及一个用户has_many产品。与当前用户查找Rails范围

在我的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 

有没有更优雅/标准的做法?

回答

5

如果你在你的很多控制器运行这段代码,你应该让它的过滤器之前,并定义一个方法,这样做在你的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,它有一个accessible_by范围,它接受一个能力(一个控制用户可以做什么和不能做什么的对象)并返回记录该用户有权根据您自己编写的权限进行访问。这可能真的是你想要的,但是剥离你的权限系统并替换它对你来说可能或不可行。

2

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

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({})

+0

Product.scoped可以取代1 = 1 – klochner

+0

@klochner除了它只会在链中的第一个调用时工作:(作品:'Product.for_user(...)',不:'Product.enabled.for_user(...)') – mbillard

+0

mbillard - 不正确,尝试一下 – klochner

20

我喜欢这样做如下:

class Product 

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

end 

这允许你写在你的控制器如下:

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