chaps-io / access-granted

Multi-role and whitelist based authorization gem for Rails (and not only Rails!)
MIT License
775 stars 41 forks source link

README should provide promised "cannot" example. #48

Open jrochkind opened 6 years ago

jrochkind commented 6 years ago

README says:

Note: cannot is still available, but has a very specifc [sic] use. See Usage below.

However, no example is actually given of cannot in Usage or elsewhere. Controller/view method cannot? is described, but not the quite different cannot method in permission definitions.

At first I thought cannot was maybe not actually there, the README reference was wrong or I misunderstood it.

But then I saw it in the specs. Apparently it does exist, hooray!

But the README needs a short explained example as promised. :)

pokonski commented 6 years ago

Hey @jrochkind! You are correct, there was an example of cannot but it got mistakenly removed along the way :scream:

jrochkind commented 6 years ago

Thanks! I actually could really use a cannot example!

I tried looking through README history, this seems to be the last version that still has a cannot in it... but I don't totally understand it.

https://github.com/chaps-io/access-granted/blob/d0079b7648fe60a2341b914727189a9c67d44df9/README.md

pokonski commented 6 years ago

Okay so I'll try to explain it here, and if it makes sense I'll put it in README:

tldr; Access Granted traverses roles top to bottom, as soon as it finds a matching can/cannot in one of the roles it stops looking at the roles below it.

In the example below let's assume we want to disallow banned members from posting (and only from posting) on our forum:

            role :banned, { is_banned: true } do
              cannot :create, Post
            end

            role :member do
              can :create, Post
              # (some other permissions here)
            end
          end

we put :banned above the regular role so it take can precedence over the regular role below (:member).

Steps of the logic would look as follows:

  1. You execute can?(:create, Post)
  2. AG starts iterating over defined roles.
    1. first we check the role :banned
    2. does it have a permission defined for :create and model Post?
    3. yes it does so we use that and stop looking at roles below it
  3. AG returns result of can?(:create, Post) which is false, because cannot is a negative.
jrochkind commented 6 years ago

This is actually quite helpful, yeah. It explains what you mean by about the importance of order too, which I was confused about too. "as soon as it finds a matching can/cannot in one of the roles it stops looking at the roles below it." -- that's the important part. Thanks!

pokonski commented 6 years ago

Glad I could help :+1: