Gawyn
Gawyn

Reputation: 1156

CanCan, nested resources and using methods

In my new project, I have a resource Bet which other users can only read if they are the owners of the bet or friends of him. The main problem comes when I want to define abilities for the index action. In an index action, the block does not get executed, so I guess it's not an option.

Let's illustrate it. If I wanted only the owner to be able to index the bets, this would be enough:

can :read, Bet, :user => { :id => user.id }

But I need the acceptable ids to be a range, one defined by all the friends of the user. Something like:

if (bet.user == user) || (bet.user.friends.include? user)
    can :read, Bet
end

But this is not correct CanCan syntax.

I guess that a lot of people has had problems with CanCan and nested resources, but I still haven't seen any answer to this.

Upvotes: 1

Views: 518

Answers (2)

Amir Rubin
Amir Rubin

Reputation: 860

In your Bet model, create a method:

def is_accessible_by? (user)
    owner = self.user
    owner == user || owner.friends.include?(user)
end

Now in ability.rb, set your CanCan permission:

can :read, Bet { |bet| bet.is_accessible_by?(user) }

EDIT

As you point out, since index actions don't have an instance of the object, the block above won't get executed.

However, it sounds like what you are trying to do - list the bets owned by the user or their friends - should not be handled using CanCan or permissions. I would create a function in my User model:

def bet_listings
    friend_bets = friends.inject([]){ |bets, friend| bets<<friend.bets; bets }
    self.bets + friend_bets
end

Then in your index action: @bets = user.bet_listings

Upvotes: 1

Gawyn
Gawyn

Reputation: 1156

Just now I have found a solution, but I don't like it much. It's about creating a custom action and defining abilities for it. For example...

In the controller:

def index
  authorize! :index_bets, @user
end

In ability.rb:

can :index_bets, User do |friend|
  user == friend || user.friends.include?(friend)
end

It works, but I don't feel great about using it. Isn't out there anything more elegant?

Upvotes: 0

Related Questions