Many of us have probably encountered this situation. I want to build an app which supports multiple user roles and don't want to use gems for that process.
I have 4 types of users:
Admin
Teacher
Student
Librarian
Admin is simple and he would need only two columns, username and password. User table at the beginning contains only these values:
username, password, admin, teacher, student, librarian
Columns admin, teacher, student, librarian are booleans which define does user have certain role. Admin would have admin to true and all other columns to false.
The problem is appearing when we introduce other columns which are specific to only one role. The we have these columns for user table:
id
username
password
admin
teacher
student
librarian
teacher_column1
teacher_column2
teacher_column3
student_column1
student_column2
student_column3
etc...
When user is created we need to fill a lot of columns with null values. If we create a teacher, all columns which are needed only for librarian and student are filled with nulls.
On a couple of places when people asked about this, they were recommended to do STI so they would end with something like this:
class User < ActiveRecord::Base
end
class Admin < User
end
class Teacher < User
end
class Student < User
end
This looks much better but would still introduce a lot of null values.
Other idea is to introduce 4 new tables for different user type details. Something like this:
User table:
id
username
password
admin
teacher
student
librarian
Teacher table:
user_id
teacher_column1
teacher_column2
teacher_column3
Student table:
user_id
username
password
student_column1
student_column2
student_column3
The same for Librarian and Admin. In the process of user creation after we check role, new row in specific table for that user would be created.
What do you think about this last approach? Cons and Pros?
Would this be a correct way in creating a system with multiple user roles? Thank you.
Don't use different columns for each permission.
Create a single table for Users with these columns:
username
password
user_type
user_type will be a value in %w{admin teacher student librarian} Then use single-table-inheritence like you mentioned in your post.
Create a table for Role:
name
Then create a table to tie roles to users:
role_id
user_id
Create a table for Permission:
name
Then create a table to tie permissions to roles:
permission_id
role_id
In the end you will have:
3 models with tables: User, Role, and Permission
4 models without tables, inherting from User: Admin, Teacher, Student, and Librarian
2 tables without models: users_roles and roles_permissions
Also, if there are many columns that are unique to every user-type, then I would recommend using different model+tables for each and making the user in Role polymorphic.
That way you can easily create new roles/permissions, modify the permissions of a particular role, and easily add/remove roles for a particular user.
Related
I recently had this problem in designing a SQL database.
I want to create a database for a school, and of course not all users have the same role or privileges.
For example, there are teachers, headteacher, students and parents.
If I put all those in the same table and put a role column the table, then I can't be free to put any other columns for a specific role
like I can't add a grade column for student because the other roles don't have grades.
Also I can't put them in separate tables because in the log in I can't specify the role for this user and go to his table .
What is the best way to do something like this?
Use polymorphism on the user table.
Create a user table with basic authentication and common information like email and credentials. Now create 2 columns authority_type, authority_id (naming can be changed).
Now for every type of new role or privilege, create a table.
For e.g. In your case, there will be a table for the teacher, headteacher, student and parent. All have separate sets of attributes.
Whenever saving a user record, you'll use its authority_type and its authoriy_id ( record foreign key of that other table ).
I have 4 tables
Account
Admin
User
Role
The account table contains the email and password to login.
An account can either be an admin or an user.
An user has a registerdate
An admin has an adminnumber, but no registerdate (different attributes)
The role table contains the role name, either admin or user.
An account currently contains foreign-key relationships with all other tables. This isn't ideal, since depending on the role, one of the tables will be left empty.
I need all account to be in the same table, yet depending on the role it should have different links and attributes.
What is the best way to tackle this?
I use MSSQL
I need to create a system that allows both individual users and groups (e.g., a company) to sign up for a subscription service.
The procedure for signing up for a group membership will involve a user paying for as many users as they require (e.g., 5) at sign up. Once they have paid they will be able to create these other users (i.e., have admin functions) that will be associated with this group (e.g., other members of their company). (They will be able to pay for more users for their group at a later date if they wish.) A user cannot be in more than one group. The original person that signed up on behalf of a group can assign admin roles to these newly created members.
For login purposes, I would like to have both individual users and group users in the same table of the database. For example, it could be called and have columns (to keep things simple):
user table:
user_id
username
I then thought that there must be a second table that shows the links between users (i.e., which belong to which group). Let's say that this is:
groups table:
group_id
user_id
I am guessing that this is a one-to-many relationship as many users can be in one group, but each user can be in only one group.
In order to assign the proper roles to the user that signed up on behalf of a group there would be another table called:
roles table:
role_id
user_id
This would allow some users to have permissions of admin rather than just user. I would then just have to lookup the user_id's of the admin role (a specific admin user_id) when they logged in and this would give them access to the correct people in their group.
Before I go ahead designing this database I was wondering if this is an appropriate database design to go about creating these individual and group users or if there is a better setup?
FURTHER INFO: There are two sign up forms: an individual sign up form and a groups sign up form.
For an individual, we will record their "username", their user_type (individual) and assign them a role of "user". They do not need to be assigned a group id and we will not need to convert their membership to a group membership later on.
For the user who signed up as a group using the group sign up form, we will record their "username", their user_type (group), no. of memberships purchased (e.g., 5), a group id (e.g., a unique integer) and assign them a role of "admin". Because they have purchased multiple memberships, they will be able to create/add new users to their group upto the number purchased. They can assign each new user a role of either "user" or "admin". A role of "user" in both individal and group membership has the same permissions, so there are only two types of role.
As such, I had planned a createUser() function that creates:
For an individual: username, user_type(individual), role(user)
For a group: username, user_type(group), group_id, no_purchased, role(admin)
For a new member of a group (created by admin): username, user_type(group), group_id(the same as the admin), role(admin or user)
I had then planned to create a checkUser() function that:
Gets their id, username, etc...
Checks if they are an admin or user.
If admin, then gets the users/admins that are in the same group as them.
Most calls to the database will be to login (i.e., username/password). I was looking to see what the simplest database structure would be for this situation.
I feel like you might make your life simpler if you consider individual users as groups users with only one member. This will also give you flexibility in the future if an individual user would like to expand into a group?
On the other hand you can keep it as you have it but I wouldn't bother specifying the user type. That can be derived based on if they belong to a group or not.
Many ways to tackle this problem...
I have a ER diagram made up and it consists of USER Table and within that it is set as
User ISA admin
and
User ISA member
Admin and Member tables are both child tables of USER.
I want two usertypes, m for member, a for admin.
ADMIN will have the option to change member to admin in admin panel
ADMIN table has: admin ID(PK) and user ID(FK)
MEMBER tableconsists of
memID (PK) userID (FK) signupDate lastlogin location, age, bio
USER table consists of
ID (PK) fname lname password usertype email
What I am trying to achieve is..
Guest must register via a form on registration age and must automatically be set as usertype (m) for member.
So because I have it as
USER ISA member
USER ISA admin
Which is the best way to have registration form? should it be for two tables (user and members) which wouldbe easiest way to achieve this in words? And also can it be explained how I can make sure it is auto set a usertype 'm' for member?
For telling admin vs user, you can just use one column (user_type). You can also use the DEFAULT in your table schema to handle that.
However, if you'd eventually like a more robust permission system, i'd recommend:
TABLE users - stores user info
TABLE permissions - With (e.g., permission_id, permission_name)
TABLE users_to_permissions - A table to link the two
That way, you can explicitly assign permissions for different things:
SELECT p.* FROM permissions p WHERE permission_id IN (SELECT DISTINCT permission_id FROM users_to_permissions u2p WHERE u2p.user_id = :user_id
You can also obviously use JOIN, or whatever fits your use case the best. When in doubt, prefer normalization and extensibility over a quick one-column solution.
SqlFiddle: http://sqlfiddle.com/#!2/bddba5/2
My application has several kinds of users with different sets of properties, for example: customers and employees. One user may be belong to more than one of these roles.
So I decided to have this (simplified example) structure of my database:
users (contains the fields applicable to all different kinds of users)
id
username
email
customers (contains fields applicable to customer role)
id
user_id
shipping_address
employees (contains fields applicable to employee role)
id
user_id
salary
Question 1: Is this a good way of handling user roles with many different properties?
In reality I have six roles with sets of 7-20 properties. Some of the roles are not even conventionar roles, but bore like extra properties. If a user decides to login with a Facebook acoount, then the Facebook_account table is applicable.
Question 2: When using an ORM, in my case Eloquent, would it make sense to have the role model (customers) extend the user model?
When I fetch a customer object I really want all user och customer properties together, without having to merge them manually.