Rails scope find with current user

2019-03-11 06:24发布

问题:

I'm using Rails 3 with Devise for user auth. Let's say I have a User model, with Devise enabled, and a Product model, and that a User has_many Products.

In my Products controller I'd like my find method to be scoped by current_user, ie.

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

unless the user is an admin user, i.e. current_user.admin?

Right now, I'm running that code in almost every method, which seems messy:

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

Is there a more elegant/standard way of doing this?

回答1:

If you're running this code in a lot of your controllers, you should probably make it a before filter, and define a method to do that in your 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

I don't know what you use to determine if a user is an admin or not (roles), but if you look into CanCan, it has an accessible_by scope that accepts an ability (an object that controls what users can and can't do) and returns records that user has access to based on permissions you write yourself. That is probably really what you want, but ripping out your permissions system and replacing it may or may not be feasible for you.



回答2:

I like to do this as follows:

class Product

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

end

this allows you to write the following in your controller:

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


回答3:

You could add a class method on Product with the user sent as an argument.

class Product < ActiveRecord::Base
  ...

  def self.for_user(user)
    user.admin? ? where({}) : where(:owner_id => user.id)
  end

Then you can call it like this:

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

PS: There's probably a better way to do the where({}).