Permission System with groups, roles and users

Hi there,

i have a serious problem here. Let me explain my situation:

I have 3 Models: Group, Role, User Pretty self explaining. Every group has multiple roles (every group can define it's own roles. some have 3, some have 14 and so on..) and every role has many users through a join table.

Every group has some features like a public forum, a calender, public and private news and so on. I need to define Rules / Permissions like "roles which are allowed to post in the public forum", "roles which are allowed to create new events in the calender".... The Group admin can select 1-n roles which are allowed to do these actions. But how do i model these relations. I try to find a "good" design for this since a few days now and didn't find a answer. It would be possible to create a field for every "option" inside the groups table which stores a comma seperated list of roles... if you know what i mean. but this seems kind of "messy" to me.

there has to be an "intelligent", dynamic, RoR like way to handle this.

Any suggestions are welcome!

Thanks in advance,

Pascal

i tried to use the "method_missing" for my problem.

i created the following: table "group_options" with key:string it contains every option like "create_events_roles" as the key

table "group_options_relations" with group_option_id:integer role_id:integer group_id:integer it is the join table for the role and the group_option

i added the following method to my group model:

  def method_missing(m, *args, &block)     @option = GroupOption.find_by_key(m.to_s) || GroupOption.find_by_key(m.to_s.match(/(\w*)\?=/)[1])     if @option       if args.size != 0

GroupOptionsRelation.find_all_by_group_option_id_and_group_id(@option.id, self.id).each do |go|           go.destroy         end         args.first.each do |a|           GroupOptionsRelation.create(:group_option_id => @option.id, :role_id => a.to_i, :group_id => self.id)         end       else         return GroupOptionsRelation.find_all_by_group_option_id_and_group_id(@option.id, self.id)       end     else       super     end   end

it "does" something that i "could" use. but it doesn't "feel" right... ?> g = Group.find(4) => #<Group id: 4, title: "Test Group">

g.create_events_roles

=> [#<GroupOptionsRelation id: 2, role_id: 5, group_option_id: 1, created_at: "2008-07-15 00:15:15", updated_at: "2008-07-15 00:15:15", group_id: 4>, #<GroupOptionsRelation id: 3, role_id: 12, group_option_id: 1, created_at: "2008-07-15 00:15:15", updated_at: "2008-07-15 00:15:15", group_id: 4>, #<GroupOptionsRelation id: 4, role_id: 19, group_option_id: 1, created_at: "2008-07-15 00:15:15", updated_at: "2008-07-15 00:15:15", group_id: 4>]

g.create_events_roles [4,2]

=> [4, 2]

g.create_events_roles

=> [#<GroupOptionsRelation id: 5, role_id: 4, group_option_id: 1, created_at: "2008-07-15 00:22:20", updated_at: "2008-07-15 00:22:20", group_id: 4>, #<GroupOptionsRelation id: 6, role_id: 2, group_option_id: 1, created_at: "2008-07-15 00:22:20", updated_at: "2008-07-15 00:22:20", group_id: 4>]

hmmmm any ideas how to clean this up? Go a "better" way?

thanks in advance,

Pascal

i've seen solutions that define a role has_many permissions, where the permissions attributes include a controller+action (eg 'comments' 'new'), and then implement it as a before_filter in the controllers or site- wide in application.rb

try googling "rails acl"

linoj

Yeah the original rails recipes book covers this topic in the exact manner you specify.

@linoj: the acl plugins only cover one dimension. the role. like access_control :new => 'admin | moderator' but i need to add the group as another dimension. for example, every group has a calender and role "maintainer" of group 1 may edit the calender of group 1 but not the one from group 3. The Acl system just says "you are a maintainer, you can use the new action!" but it should say something like "you are not a maintainer of group 3, go away!!"

@Brian Hogan: glad i own the rails recipes in the original and the new version, but, i can't find a topic describing my problem. Which one did you mean?

i think i'll try a different way. i'am going to "tag" my roles with something like acts_as_taggable. if a role is tagged with "may_create_events" the user of this role "may create events" :slight_smile: hope this works

Pascal Friederich wrote:

Hi there,

i have a serious problem here. Let me explain my situation:

I have 3 Models: Group, Role, User Pretty self explaining. Every group has multiple roles (every group can define it's own roles. some have 3, some have 14 and so on..) and every role has many users through a join table.

One way to model this is defining a "context" model, that way a user has each role in a particular context, and you have an active context in each session that filters the available roles for the current user. The downside is that in some situations you might have to hardcode the current context (depending on what each view shows).

The advantage is that permissions are defined just one time if they are the same

Example:

Roles_Users table has user_id, role_id, context_id, context_value fields John has role Administrator in Group1 Rachel has role Moderator in Group1 John has role Moderator in Group2 Robert has role in Group2 Robert has role in Group1

If you only have to discriminate by group, then you don't need context_id, just the value.

Then:

Administrators can Delete Posts Moderators can Edit Posts Users can Create Posts Users can Edit Posts (if they created it)

So, in your controller, to decide if you need to display the "Delete Post" link in you post list, you need to verify that the current user is an administrator AND the "current" group is Group1.

I hope that makes sense.

Lucas.