Recently, I’ve decided to start learning Ruby on Rails (2.3.4). Things have been going along more-or-less smoothly (I’m still not sure whether or not I hate ActiveRecord, or can tolerate it, but that’s a post for another time.). That is, until I started looking into the various plugins/frameworks for doing Authorization in Rails.
After searching around for a bit, the two main contenders I found were rails-authorization-plugin, and acl9. acl9 seemed to be, by far, the more commonly recommended of the two.
I wasn’t really impressed with the Apache style allow/deny used by acl9. Just wasn’t what I was looking for with my project, so I started looking at rails-authorization-plugin. This is where I ran into trouble.
rails-authorization-plugin allows you to assign roles for objects, and have an optional scope. For example:
1 2 3 4 5 6 | |
So far, so good.
Now, let’s check what roles this user has:
1 2 3 4 5 6 7 8 9 10 11 | |
Wait? What? That’s right: Inheritance of roles flows from instance, to class, to global. If you have a role for any instance, you also have it globally. This is completely backwards from what I would have expected, and from what I wanted.
Ok, time to go back to looking at acl9. Guess what? It does the exact same thing. Given these findings, I did what any developer, with access to Git would do. I forked the code to make it do what I want. Thus my fork of rails-authorization-plugin (and it’s tests) was born. I decided to base my changes off of rails-authroization plugin, simply because I didn’t like the Apache style allow/deny syntax of acl9.
Now, given the initial role assignments above, we get the following:
1 2 3 4 5 6 7 8 9 10 11 | |
Inheritance is handled as follows: Global -> Class -> Instance. If a role is assigned at a “higher” level (further left), then it applies at all levels “lower” than it (further right).
While I was in there monkeying around, I decided that I didn’t like strings as role names. They seemed a little more special to me than just plain old strings.
Now we can use symbols as role names:
1 2 | |
Things still didn’t quite seem right though. The whole role to scope mapping seemed like it deserved to be emphasized a little more, and assigning multiple roles at once was a little clunky.
Now we can use hashes for assignment, and lookup:
1 2 3 4 5 6 | |
This actually demonstrates two things. First using a scope of
nil, is the same as saying that the scope is global. Secondly,
when doing has_role? with a hash, all role requirements must be
met for has_role? to be true.