Rails, Devise, CanCan or Declarative authorization - ruby-on-rails

I am developing a app in ruby on rails, and I reached a point where I don't know what is my best solution for the fallowing scenario. So far I am able to create Users, create projects, associate users (something like on FB), I am able to invite users to my website and now I would like to allow users to give different levels of access to projects that they created, to other users(something similar with github). Also the users after creating the account they will get a role of superadmin, like that they will be able to manage their on projects, or assign projects to their associates. So which will be my best option between cancan and declarative authorization. Also do I need a table which will store the user_id, role_id, and project_id if I will use cancan or declarative authorization?
Thank you
I will explain my problem better.
So far I have User (with devise) which are able to create projects. So, if user1 creates project A and project B I want him, to be able to assign user2 with role admin on project A, and user2 with moderator role on project B.
I was thinking in creating a UserRoleProject link table, is it a good idea? Or if not please help me with some pointers.
The action will be something like, User1 select from a list user2, select a project from another list(that user1 created), and select the role that the user2 will have on that project.
Any user will be able to perform the same action on their projects.
Also there will be n projects and n users and 3 access levels(admin, moderator, guest)
Thank you

I once made a huge app with allot of roles and each role had its sets of available actions, and i used devise and cancan and they work like a charm, they integrate quite well and both have great documentation.
for the other question you can do something like this
project model:
has_one :user
has_many :collaborators, :through => :team
team model:
belongs_to :user
belongs_to :project

Related

How can you set up a multi-tenant Rails app without using subdomains?

I'm trying to create a SAAS e-commerce tool with a backend for staff that also allows customers to have accounts and checkout on the front end. I'm struggling with how to design this so that the Company, Account Owners, Staff, and Customers are all siloed off to each Company, while also having the appropriate restrictions based on their roles.
From what I've read so far most of the rails solutions use multi-tenant patterns with subdomains, such as the Apartment gem, to silo off accounts. But it seems simpler to just have your site use one big app and database. For instance Basecamp recently switched to this approach with Basecamp3. Newer apps seem to be built this way.
And, should the admin features and the customer accounts / front end shop be separate apps completely, or can you do this with a "majestic monolith"? One big app and database, while large, seems more straight forward to me.
I found this blog post that explains how to do something like this with Pundit, but I'm still having trouble groking the big picture of how this could work with Account Owners, Staff, and Customers all in the same app.
Here are the basic needs for my app:
User Roles
Account Owner (creates the company's account and has full access to their company's data)
Staff (invited to join a company and doesn't have access to some of the company's data, such as billing information)
Customer (can sign up for the site and view products, add the them to cart, but can't access any of the staff or account owner features.)
All Users (no matter the role) belong to a Company and can't access another company's data. (Thus providing the the ability to run separate stores on the same app, which is needed to run this as a SAAS app.)
Account Owners and Staff can CRUD Products, but not Customers.
A great analogy would be how Shopify's admin area and customer accounts currently work for shop owners, but unlike Shopify, it doesn't require using subdomains.
Potential Models and Associations
Company
has_many :users, dependent: :destroy
has_many :products, dependent: :destroy
User
belongs_to :company
Product
belongs_to :company
Authorization
Would it work to use Pundit to restrict the controller actions based on User roles and then ensure that data is siloed off via the Model associations?
Signup Flow
I'm a little fuzzy on how to handle scoping the different User roles and where the "staff invites" and "customer" sign up could fit into a sign up flow.
Would this approach work?
Create separate controllers for "Account Owner Signup," "Staff Signup," "Customer Signup," and then embed my signup form into those views. (Using Clearance for authentication and would like to keep that if possible, but just augment it as needed).
Account Owner Signup: So if a someone signs up through the New Account Signup controller (with embedded authentication form) they would also create a Company.
Staff Invite: The Account Owner can create new Staff Users by inputing a Name and Email address. This creates a new User with the role of "Staff" (and thus cannot become Account Owners on another account). The new "Staff" user is sent an invite email that is basically password reset email inviting them to accept the invitation by creating a password.
Customer Signup: If someone signs up through the "Customer Signup" controller, they would automatically be given the user role "customer". Not sure how to set the Company ID in this case. (Pass the company_id as a hidden input on the customer sign up form?)
Is there a better way to design this type of app that I'm missing? Am I on the right track? I have no experience building something like this so any clues would be extremely helpful.
It seems like newer apps follow this type of pattern for multi-tenancy rather than subdomains.
You open with simple e-commerce site but the questions you're asking indicate that you're looking for something that's a little more complex :) You're on the right track.
The acts_as_tenant gem is worth a look. We use this now and it helps make sure your queries are all scoped appropriately.
I would also look at & evaluate rolify if you need to do roles (but don't rule out a boolean flag on your user as well).
I wouldn't rule out devise, but clearance is quite popular.
Using a subdomain might be unrealized work depending on the amount of effort, unless you need to actually use subdomains for vanity purposes (my.example.com vs example.com/my), you can do multi-tenancy without it.
I would consider separate controllers & namespacing for the different roles if their access varies wildly; you can also combine them into singular controllers using Pundit (but this could be unwieldy). You'll still want to use Pundit, however, Pundit can do things like scope the records a user should see.
You're on the right track and asking the right questions but the answers to all of these will depend on other questions (that you probably can't even answer right now).
I have a project where I'm doing what you noted (pundit to restrict data, acts_as_tenant to silo things) but as it develops certain patterns emerge that lead me down a different path. Namespacing admin, rather than doing admin checks inside the same controller for example; because if you re-write to an API you end up trying to make the same endpoint do different things and it's much cleaner to separate out the 2 endpoints behind a namespace & document the actual behavior in my opinion.

Parent/Child classes in Devise

I'm newish to Rails and working on a project that I would like to create a parent/child relationship using devise. I've looked through a good bit of the literature on Devise, but didn't see any clear cut way to do what I'm trying to accomplish (though it's certainly possible I overlooked the answer because I was using different terminology).
Here's what I'd like to do:
Companies sign up using the normal devise registration flow with a little extra information - i.e. Company name, address, etc. They then add 'users' once inside the application. Users shouldn't have an external sign-up flow. I would like to each user to inherit the company information from Company.
Here is what I thought I'd try:
Generate both the Company and the User devise models.
Generate the User controller, modify the new action to #current_company.user.build
Would this accomplish what I'm trying to do?
Any further reading that you might be able to pass along would be appreciated!
Do this....
#app/models/company.rb
class Company < ActiveRecord::Base
has_many :users
end
#app/models/user.rb
class User < ActiveRecord::Base
devise ....
belongs_to :company
end
This is a has_and_belongs_to_many association.
What you should be doing is leaving companies to be its own model; don't include Devise on it at all.
Instead, you should make your User model the only one with the authentication. After that, each user will have to be related to a particular company (or if you wanted to use has_many :through, you could have a user a member of many companies).
You'd have to scope the Devise authentication around a company (IE company.users.exists? user); I've been working on that but don't have a thorough implementation yet.
There's a good ref here: Scope login to subdomain
This will allow you to have users for a particular company; which you'll be either be able to scope using subdomains (to make a crude "multi tenant" app), or to have a select box at sign-in or something.
Obviously, your lack of input means I've got to write a broad answer.
If I were you, I'd think about your desired flow.
Research multi tenancy with Rails (the apartment gem is good if you're using PGSQL) - this should give you a better idea on the way the application should work (IE how does a company need to support users).

Devise + STI + Authorization

I have the following situation:
My app has several types of users: Owner, Team Member, Collaborator, Client, and Guest. (the Guest type isn't relevant for this question)
These are the connections between the different models:
Owner belongs_to Account
Account has_many Team Members
Account has_many Projects
Projects habtm (or hmt) Collaborators
Project habtm (or mht) Clients
There are four key functions I need for my authentication & authorization:
Be able to upgrade a Collaborator to a Team Member (this means removing all habtm's to Projects, and add a belongs_to to Account
Be able to have different Devise strategies for different users (Owners have registerable, clients do not)
Have different login pages which only accept a subset of users (separate login for owner/team members/collaborators and clients)
Be able to call the different subset of users using Account.owner, Account.team_members, Project.collaborators, and Project.clients
I have gone over several solutions in my head, but I am unsure which would work best in my situation.
At first I thought about using Devise for both the authorization and authentication, but I figured I'd better use something like CanCan for the authorization part.
I also considered using one table for each user type, but that would make it harder to change roles after initial creation
I am now dubbing on using STI fo have TeamMember < User, Client < User, etc. But since Clients and Collaborators belong to Projects and Owners and Team Members belong to an Account, I am not sure that will work easily with STI, and I also haven't really found any good examples on Devise with STI.
Any ideas how to solve this situation?

Ruby on Rails login

for a university project i have to create a small ruby on rails application, in Netbeans, which allows staff of the university to maintain their absence records.
The sample logins available in books have been regarding a singular user table. My application will require 3 types of users staff (who are assigned to a manager), manager and admin (to create/edit/delete all employees). Thus the login will have to bring up a particular users home page, in steps my confusion.
My table structure at the moment has the field user_id in both the manager and staff table which has a 'has_one' relationship with ID of the users table which simply contains the fields user_id, user_name password and user_type.
I can't get any adapted sample code for logins to work with this multi user application, any insights or ideas on tutorials available similar to this?
Cheers.
P.S. I have the full spec available if any other further information is required.
I couldn't tell from your question if you already have authentication working.
But, I've set up similar systems using the devise and cancan gems.
With devise, you just need to specify the root path in config/routes.rb and your user will be redirected there upon signin. For example you could have a route like this:
namespace :user do
match 'dashboard' => 'dashboard#index', :as => :root
end
Then, in dashboard#index, you could provide profile-specific actions. Also, a good way to manage user roles would be to put a role column on the users table and use the cancan gem.
Check out this railscast on the subject http://railscasts.com/episodes/192-authorization-with-cancan... So you could assign someone to the admin role, and using cancan's simple DSL they could create/edit/delete all employees.

Roles that are User<>Project Based

Currently I'm using Devise & CanCan which allows me to create
Users with Roles using a (Roles_Users) table.
That's nice, but what I want is to Have Projects in my app and for
each project for a user to possibly have a role like (Admin, Viewer,
etc) IE, roles are not assigned to users but to users based on what projects they are a member of.
Examples:
User X belong to Project A with an Admin Role
User X belong to Project B with an Guest Role
User Y belong to Project B with an Observer Role
What kind of Model would work for this?
Models
Users
has_many: projects
Projects
?
Roles
?
Users_Roles_Projects (user_id, project_id, role_id)
What do you think? I'm a newbie and could use the understanding and
thinking from you fine experienced folks. Thanks!
You should have a look in to has_many :through. This Railscast should get you up and running: http://railscasts.com/episodes/47-two-many-to-many
For example, you could have User has_many Projects through Memberships (I'm sure you can come up with a better name!)
Your Users model would contain the standard user details, the Projects model would contain the project details and presumably you have some Roles model somewhere (I've not used either of the libraries you mentioned so I can't comment in terms of how they work). The key is the Memberships model.
The membership model would contain the userID, projectID and a roleID. In the database there should only be one instance of any given userID and projectID pairing so by storing the roleID along side this pairing you can assign the role to that user on the specified project.

Resources