role model is a gem that lets you add roles to the user as a method and saves the role into a field on the user table as a bitmask
that is , lets say you have and array like this
ROLES = %w[admin moderator author banned]
this gord in your user model and you have a field in the user table called roles_mask
as you see you can map the roles in the array as a series of bit
[admin moderator author banned]
0 0 0 0
if a user is admin the in his roles_mask field is this
1000
in binary which translate to 8 in decimal format, if the user is
admin and moderator the value is
1100
and that is a 12
As you can see there is no reason to have a roles table in the proyect unless you have
like 20 or more roles.
role model saves the roles with a virtual attribute, roles that is in you user model and is looks like this
def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
end
as you can see it maps the array in ROLES to a binary array and saves it in the roles_mask field of the users table
to read a role it does this
def roles
ROLES.reject do |r|
((roles_mask || 0) & 2**ROLES.index(r)).zero?
end
end
this returns an array of strings when ever it finds a 1 in the binary representation of the string array that is saved on the
roles_mask field
I understand what you mean, but can't suggest a solution that I've
done myself (as I've tended to work around the flat, "user has a
single role" model). But take a look at Redmine, as it has the same
model that you're after (where a user can be an administrator on one
project, but a contributor on another, while having no permissions on
a third), and the source code could give you some ideas.
role model is a gem that lets you add roles to the user as a method and
saves the role into a field on the user table as a bitmask
that is , lets say you have and array like this
ROLES = %w[admin moderator author banned]
this gord in your user model and you have a field in the user table
called roles_mask
[...]
Wow, what a bad idea. Remind me never to use that gem if that's really
the way it works. Storing multiple values in one DB field (which is
essentially what the bitmask is doing) is generally not a good thing.
Marnen, in your example models above, permissions is the name of the
table correct? that I create?
I ended up calling it: projects_users_roles
class ProjectsHaveAndBelongToManyUsersWithRoles <
ActiveRecord::Migration
def self.up
create_table :projects_users_roles, :id => false do |t|
t.references :project, :user, :role
end
end
def self.down
drop_table :projects_users_roles
end
end
Just want to make sure I'm understanding how to set something like
this up in Rails. Thxs
Marnen, in your example models above, permissions is the name of the
table correct? that I create?
Yes.
I ended up calling it: projects_users_roles
That's not a good name. If your table needs a model (as here), then you
should take the time to find a descriptive name for it -- which is why I
used Permission.
Better way to phrase the question... Given the model above,
Knowing the project_id and user_id, how in Rails using activemodel can
you query to obtain the user's role if any, meaning return admin or
nil
I'm trying things like in the users.rb:
logger.debug self.permissions.find_by_project_id(1)
But that doesn't give back a role...
Of course it doesn't. You asked it for a Permission object, and that's
what you're getting. You want the Role that that Permission belongs to.
So...can you figure it out now?
Tricky stuff!!!
No, actually, this is very simple. If you find it tricky, you need to
think more clearly about the structure of your associations and queries.