Setup for roles and authorization
This is my first question for the community. I'm super excited to be here and hope to be answering a few of them myself as well.
I'm working on a rails project where people can work on a project together - books to be specific. I have a need for the following roles:
- An admin/support role, someone from customer support who can dive into any project and help managing a project whenever they're contacted with a question
- An editor, someone who has rights to manage the content in the book and who can invite/manage people who can contribute to the project
- A contributor, someone who can add content to the book, but who doesn't have the ability to see what others contribute, nor manage any of the contributors. They're simply asked for input and that's it.
I have a model called User set up with Devise.
My challenge is that both editors and contributors can have multiple projects: an editor could be an editor for project A, but a contributor for project B and C. A contributor could likewise be a contributor for project A and an editor for project B and C. A user can't be both an editor and a contributor for one project. (However, I can imagine the requirement popping up that my client wants an admin to be able to 'view as editor' or 'view as contributor.' - but that's for later concern)
I had previously set up an enum role column on the User table, but this doesn't take into account the fact that a user can have different roles for different projects. I'm looking into creating a different roles table, but I wonder what my best options are.
My research has led me to Cancancan and Rolify together, but I fail to understand the difference between them and whether I could also just use either of them. In the tutorial from Chris, I also understand that Cancancan has a role functionality. Would I really need Rolify then?
I'd really appreciate any advice in the right direction! I've been wandering the internet for a while now, haha.
Something you may consider is adding another table,
ProjectMembership and then setup
has_many :through relations between your users and projects via that table.
class User < ActiveRecord::Base has_many :projects, :through => :project_memberships has_many :project_memberships end
This should take care of your problem of a user having various roles based on the particular project their assigned. Check out this SO for additional details: https://stackoverflow.com/questions/11600928/when-should-one-use-a-has-many-through-relation-in-rails
I don't have a ton of experience with cancancan/rolify, but based on my understanding they kind of serve different purposes so you will probably want to use them together. Cancancan is focused on authorization which you scope based on the roles you setup with rolify. So you let cancancan manage authorization logic, and let rolify manage the role logic.
Thank you so much for your reply!!
Would you say that a ProjectMembership table is all I need, or does Rolify add any features that I might need later on? I'm kind of confused as to whether I need/could really use a gem or if adding a table would be sufficient.
I do think that I now understand the difference between Rolify and Cancancan. Based off of Chris his tutorial on this, it does seem like Cancancan has a way to define roles for users. This makes it seem to me that Rolify is not necessary anymore?
Sorry for another question 😁
No worries at all, this stuff can be confusing!
It kind of depends on what your final needs are and the level of granularity you need. I'd say if you can control all foreseeable actions by a simple enum role system, then just roll with that on your
ProjectMembership model and let cancancan handle all the logic from there.
Unfortunately, I don't have enough experience working with either of them to give an example of some of the nuances, my usual setup is just an enum role + action_access gem since my needs are usually pretty simple.
I'd create a dummy app and do a few quick tests of the model configuration + cancancan and see if you can hammer out a few expected situations and see how it works out for you. If you hit a snag, see if that's something that Rolify could help out with. Tinkering is my favorite part of the process! :)
Thanks Jacob! Very much appreciated. I think you're right and I should 'play' more in order to find out what works best for me.
Out of curiosity, would you recon ProjectMembership is a better name for the table than Roles? Is this a certain convention that Rails developers would prefer?
Thanks for your swift responses!
Not that I'm aware of, I think the first time I typed it I did
ProjectRole but then changed to
ProjectMembership just for the sake of continuity between the article and what was being said here.
For this case, I'd say it really depends on what else you may need this table to do for you. If all it's going to do is manage the roles and absolutely nothing else, then
ProjectRole is probably the most descriptive. However, if you plan on storing other info there as well, maybe activity the users activity or some preferneces that are particular to that project/membership relation, then a different name would probably be more appropriate since it's doing more than just handling roles.
Just letting you know that I've figured it out! Turns out I didn't need Rolify at all. I've made a table called Project_users that has a has_many through relationship with Users and Projects. On the Project_users table, there's a role column for owner, editor and contributor. It works beautifully.
Thanks for pushing me in the right direction!
Excellent!! Glad to hear you got it working, and good to know Rolify isn't necessary for this kind of setup.