Hi I'm using rolify and have just realized that I'm not actually taking advantage of it's full potential.
At present I am doing things in my controller like re-routing users if current_user.has_role? :whatever_role
, and allowing users if they have whatever other role...
Someone asked a question on stackoverflow about rolify and when I got to trying to answer it, I realized that I'm doing it wrong.
Now, here is where my confusion starts... Inside of ability.rb I have:
user ||= User.new # guest user (not logged in)
if user.has_role? :consumer
can :manage, Review
else
can :read, Review
end
Now let's say I add the consumer role to a user:
x=User.last
x.add_role :consumer
# => #<Role id: 10, name: "consumer", resource_id: nil, resource_type: nil, created_at: "2013-04-18 23:00:46", updated_at: "2013-04-18 23:00:46">
Right, so the role is created. I can check this by doing:
x.has_role? :consumer
=> true
Now I would expect this to give management ability for reviews...
x.has_role? :consumer, Review
=> true
but not for other models... here I try products
x.has_role? :consumer, Product
=> true
Further, when I look at "resource roles querying" and try to query the applied roles for reviews I find no applied roles:
Review.first.applied_roles
=> []
Can someone please explain rolify to me. Thanks
My answer, garnishing the question from this reddit post:
Authentication is establishing a
User
is who they claim to be.Authorization is establishing that a
User
can perform a given action, be it reading or writing, after they've established their identity.Roles are just common patterns of authorization across users: this
User
can be authorized as such, thatUser
can be authorized like this instead.The ingredient you're missing here is Permissions: a relationship between an established
Role
and some controller action.Roles
themselves make no promises about what action aUser
can perform. And remember--authorization is all about actions.Roles
generalize what kind ofUser
you're dealing with. They exist to keep you from having to query everyUser
for a giant laundry list ofPermissions
. They declare: thisUser
is aRole
! Of course they havePermission
to do that!There are many types of
Permission
. You can store them in a database if you want your sufficiently authorizedUsers
to be able to edit them, along with yourRoles
if those too ought to be configurable. Or, if yourUser's
Roles
are sufficiently static, you can managePermissions
in advance with Ruby code:When I want to have configurable
Roles
andPermissions
, i.e. for a client application you're handing off to someone at completion of contract, I implement aUser :has_many Roles
and aRole :has_many Permissions
with my own custom models, and then add abefore_filter :authorize
hook into myApplicationController
, and write anauthorize
method on it that knows how to martial these expectations, or render a 403 page for those people who insist upon manually entering urls to things they hope exposeactions
to things they oughtn't have access to.When I want to just have configurable
Roles
, I use Ryan Bates' CanCan gem.When I want to have predetermined
Roles
andPermissions
, I use Rolify in conjunction with Nathan Long's Authority, to get delightfully flexible Class-basedPermissions
via Authorizer classes.Both
Roles
andPermissions
can be either class-based or instance-based, depending on your use-case. You can, say, with the abilities ofrolify
you've just discovered, decide thatUsers
may only act as aRole
in certain, instance-based circumstances. Or, generalRoles
ofUser
may only be able to execute an action given the object they are trying to action is of a certain type.To explore the permutation of these, assuming a blog application, following the formula
a
User
who is a/anRole
class/instance
canaction
a/an/all/any/that (class/instance
)Permission
:Role
class andPermission
class:A
User
who is anAdmin
candelete
anyPost
.Role
class andPermission
instance:A
User
who is anAdmin
canedit
allPosts that they approved to be published
This would be easier if published posts had an
approved_by
field pointing to aUser
id. (Use a state machine gem for this sort of situation.Role
instance andPermission
class:A
User
who isan Author of a Post
cancomment
on anyPost
Note that this sort of situation is rare, which is why there are no gems I've mentioned above to handle this situation, except for perhaps the ability to manage predetermined circumstances like
Rolify
andAuthority
in conjunction; or, if you must pass this decision on to your client, your own custom solution.Role
instance andPermission
instance:A
User
who isan Author of a Post
canedit
thatPost
.TL;DR:
Rolify
is just for roles: groupingUsers
byPermission
: access to a controller action. You have yet to decide how you are going to managePermissions
.I hope this helps your understanding of
Rolify
's position in the grand scheme of authentication and authorization!