2011-11-18 159 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])