It wasn’t long until Pubb - the “private hub for offline groups” app I’m working on – needed to authorize users in a systematic fashion.
The problem goes like this: There are group owners, and there are group members. An owner can do anything, such as invite other members. Members, however, cannot. At least by default; some groups may want to allow members to invite, while some may even want their group to be publicly joinable. It all depends, so it all needs to be configurable.
There could be other roles, too. A manager could have permission to add/remove members. A moderator could have permission to edit/move/delete other member’s posts. And so on.
To solve this efficiently, we need what’s called Role-based access control – also known as a Roles & Permissions System (RPS henceforth).
Now we have two problems
Without a proper plan, implementing a RPS can get pretty hairy, pretty fast. A role can have many permissions, but a role should also be able to “inherit” roles from another. For example, our `owner` role should be able to do everything a `member` role can.
Also consider that you should allow owners to create their own custom roles. The only static data in this RPS is the list of available permissions.
With that in mind, sometimes solving a problem elegantly is a simple matter of knowing what’s possible. Fortunately, I have experience with Prolog, and already know it’s perfect for the job.
Prolog: The Little Language that Could
Prolog is not so much a programming language as it is a standardized system of specifying and querying data relationships. You can think of it as a futuristic control-flow construct, like an advanced “for” loop that implicitly finds matching answers.
Theoretically, you could write a whole app in Prolog (using SWI Prolog, for example). But the great thing is, you don’t have to. Because it’s a standard, Prolog exists in many forms and languages, such as JavaScript, Rust, and – relevant to this post – Ruby.
Ruby-Prolog is a little gem I picked up as maintainer. It’s an implementation of Prolog, written in fewer than 500 lines of Ruby with no dependencies. That makes it extremely lightweight and easy to add to any existing Ruby project – including Pubb’s Ruby on Rails codebase.
The Result
Without diving too far into the details, I now have a fully working RPS using 8 lines of Prolog and 40 lines of Ruby. It loads a set of rules from the database, and exposes a `has_permission?` method that returns true or false for a given role and permission. A Rails controller calls that method. If true, all is good. If false, the app sends an unauthorized
response, informing the user which permissions they’re missing to access that action or page.
And best of all, the code is pleasant and readable.
If you want to get a taste of Prolog, I recommend you check out a beginner tutorial like Learn X in Y minutes, get inspired by watching Production Prolog, read over how to write an RPS in Prolog , and perhaps give TheClause a follow and me a subscribe :)