Question

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

Was it helpful?

Solution

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, that User 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 a User can perform. And remember--authorization is all about actions. Roles generalize what kind of User you're dealing with. They exist to keep you from having to query every User for a giant laundry list of Permissions. They declare: this User is a Role! Of course they have Permission to do that!

There are many types of Permission. You can store them in a database if you want your sufficiently authorized Users to be able to edit them, along with your Roles if those too ought to be configurable. Or, if your User's Roles are sufficiently static, you can manage Permissions in advance with Ruby code:

  • When I want to have configurable Roles and Permissions, i.e. for a client application you're handing off to someone at completion of contract, I implement a User :has_many Roles and a Role :has_many Permissions with my own custom models, and then add a before_filter :authorize hook into my ApplicationController, and write an authorize 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 expose actions 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 and Permissions, I use Rolify in conjunction with Nathan Long's Authority, to get delightfully flexible Class-based Permissions via Authorizer classes.

Both Roles and Permissions can be either class-based or instance-based, depending on your use-case. You can, say, with the abilities of rolify you've just discovered, decide that Users may only act as a Role in certain, instance-based circumstances. Or, general Roles of User 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/an Role class/instance can action a/an/all/any/that (class/instance) Permission:

  • Role class and Permission class:

    A User who is an Admin can delete any Post.

  • Role class and Permission instance:

    A User who is an Admin can edit all Posts that they approved to be published

    This would be easier if published posts had an approved_by field pointing to a User id. (Use a state machine gem for this sort of situation.

  • Role instance and Permission class:

    A User who is an Author of a Post can comment on any Post

    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 and Authority in conjunction; or, if you must pass this decision on to your client, your own custom solution.

  • Role instance and Permission instance:

    A User who is an Author of a Post can edit that Post.

TL;DR:

  • Rolify is just for roles: grouping Users by Permission: access to a controller action. You have yet to decide how you are going to manage Permissions.

I hope this helps your understanding of Rolify's position in the grand scheme of authentication and authorization!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top