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.