I'm having some trouble defining permissions for my albums#index action. The path to it is /user/:user_id/albums - this is the ability for my :show action (:read => [:index, :show]) which is working well. The path to it is /user/:user_id/albums/:id/.
can :read, Album do |album|
@user.friends_with?(album.user_id)
end
I'm not sure how to write a similar rule for the index action, or if I even want to use CanCan here. The rule is:
current_user MUST be .friends_with?(user_id) to view any albums belonging to user_id.
user_id is of course taken from params[:user_id]. Note: /user/eml/albums/ would be the path, I'm not fetching users by their .id but by their .username!
class Ability
include CanCan::Ability
def initialize(user)
@user = user || User.new # for guest, probably not needed
@user.roles.each { |role| send(role) }
end
def user
can :read, Album do |album|
@user.friends_with?(album.user_id)
end
can :manage, Album do |album|
album.user_id == @user.id
end
end
end
UPDATE: Turns out the solution is really simple, I was just not paying attention to my routes:
resources users do
resources albums
end
In the controller that becomes pretty easy then:
load_and_authorize_resource :user, :find_by => :username
load_and_authorize_resource :album, :through => :user
And the rule:
can :read, Album, :user_id => @user.friend_ids # I don't need @user.id
I'm not perfectly happy wit开发者_JAVA技巧h it though, as using the user.friends_with?(other_user) method would be much quicker and doesn't have to fetch (potentially) a thousand ids from the database. Any other solution is most welcome.
On IRC you told me that the .roles_mask isn't important... then shouldn't this be something like:
class Ability
include CanCan::Ability
def initialize(user)
if user
can :read, Album, :user_id => [user.id] + user.friend_ids
can :manage, Album, :user_id => user.id
end
end
end
精彩评论