开发者

acl9 find just model object which satisfys object.accepts_role?(role_name, current_user)

I'm pretty new to rails and it's the first time I'm actually using authlogic + acl9. I followed the default installation steps for both plugins.

So far everything works great, but I have trouble to find an elegant solution for this problem:

Let's say I have a model class called Products. When creating a new Product object I assign the current_user as the owner:

current_user.has_role! :owner, @product

I registered a second user and made sure that this part worked.

In the products controller I have an index method, simply returning all products:

def index
  @products = Products.all
end

My question is: How do I call the find method on Products in order to get just those p开发者_JS百科roducts where the current_user is the :owner? So I using the acl9 interface that would mean:

@product.accepts_role?(:owner, current_user)

One possibility probably would be to first retrieve all products and then create a new array with just the current_user ones. so maybe like this:

@products = []
products = Products.all
products.each do |p|
  @products << p if p.accepts_role?(:owner, current_user)
end 

This solution seems pretty wasteful. So what's the right way to do it?

Thanks everyone!


how about doing all in one query:

@products = Product.all.select { |p| p.accepts_role?(:owner, current_user)}

but the idea remains as proposed by yourself


I've recently came to the same conclusion in a project I was working on.

I was tempted to do some joins on the role and role_user tables against the products table, but ended up going with the above approach.

Works well now, but it won't scale well.


I'm not sure why you want to do any joins. If you've followed the default setup for acl9, you should have many-to-many relationship between user and his roles, and many-to-one between roles and each authorization object. So if you have all relationships properly specified in your models, you should be able to retrieve the objects with something as simple as

current_user.roles.find(:first, :conditions => { :name => 'owner' }).products

You may need to specifically describe products as a named scope or association in the role model, and you can simplify the whole thing even more by wrapping that finder into a named scope as well.


Add these scopes to your Product model:

scope :roled_by, -> ( r, u ) { where id: u.role_objects.select(:authorizable_id).where( :name => r, :authorizable_type => self ) }
scope :owned_by, -> (u) { roled_by :owner, u }

...and call it like: Product.owned_by current_user - you can use that same pattern to add as many other role scopes as you like (or just call Product.roled_by :owner, current_user if you prefer).

Oh, and notice that I've used the default role_objects method, if you've set this to something else (as it's very common to do) then adjust that in the scope.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜