in my rails app (I use devise and cancan), each (registered) user belongs to exactly one role ('Administrator' or 'Users') but to at least one group (something like 'Family', 'Friends', 'Co-workers'). At runtime, when a new folder (see below) is created, a habtm relation to one or many groups can be set, which defines who can access the folder. Selecting no group at all should result in a world-wide accessible folder (i.e. users do not have to be logged in to access these folders). But right now, I don't know yet, how to define such world-wide accessible folders in my ability.rb, because I do not know how to define "can read folders which have no groups associated to it".
The relevant snippet of my app/models/ability.rb
looks like this:
user ||= User.new
if user.role? :Administrator
can :manage, :all
elsif user.role? :Users
# user should only be able to read folders, whose associated groups they are member of
can :read, Folder, :groups => { :id => user.group_ids }
else
# here goes the world-wide-accessible-folders part, I guess
# but I don't know how to define it:
## can :read, Folder, :groups => { 0 } ???
end
The relevant snippet of my app/controllers/folders_controller.rb
looks like this:
class FoldersController < ApplicationController
before_filter :authenticate_user!
load_and_authorize_resource
Can someone give me a hint?
I had the same problem just the other day. I figured out the solution after reading the CanCan readme, which you should do if you haven't yet.
You can view my solution here: Context aware authorization using CanCan
To give you an answer more specific to your use case, do the follow:
In your application controller you need to define some logic which will pick your abilities.
You'll then need to create a new ability (or abilities) in your app/models/ folder. You can also do cool stuff like this:
Where current_group_relation is defined in app/controllers/groups_controller.rb. This will give you specific abilities for specific controllers. Remember that a parent classes can call methods in child classes in Ruby. You can define a method in your controller, and call it from ApplicationController, as long as you are certain what controller is currently being used to handle the request.
Hope that helps.
EDIT: I wanted to show you what a custom ability looks like.