Reputation: 211
I'm new to Ruby on Rails and have been following the tutorial. But I need more information.
I'm building an application that will allow access to various types of users, they are, students, parents, teachers and Administration (all have the same attributes) So far I have a model for User, which has fields, Email and Password, which serve as credentials to log into the site ..
Then I have a template for each type of user. Model Student Model Teacher ....
What I wanted to know was how do I register a user, referring to each type of user, and I already have a table User.
I've been searching and I realized that using 'devise' would be a viable solution, but do not quite understand how this works.
Someone explain to me the best way to do this?
Upvotes: 20
Views: 14351
Reputation: 1814
In its most simple form, you want to be able to select the type of user when registering it.
class User
belongs_to: user_type
end
class UserType
has_many: users
end
Based on that simple one-to-many relationship, you can pass in the user_type in the form to the controller and let the controller take care of creating/associating objects
user = User.create(params[:user])
user.user_type = UserType.find(params[:user][:user_type])
That's some very simple and quickly put together code with intention to make my point a bit clearer.
Upvotes: 0
Reputation: 10952
There are several ways to approach this problem, as other answers indicate. First, make sure you understand the difference between authentication, (creating a user and logging in), and role-based authorization (controlling access to different parts of the web application depending on the user's role). You can implement authentication yourself but most Rails developers use the Devise gem because it is robust, full-featured, and well-tested. Authorization can be implemented with simple additions to a User model, though developers often use the CanCanCan or Pundit gems for complex applications.
For the use case you describe, I recommend implementing a very basic form of role-based authorization in your User model. First you'll have to create a User model using Devise.
A new feature of Active Record, Enum, introduced in Rails 4.1, is the simplest way to implement role-based authorization.
Create a migration:
$ rails generate migration AddRoleToUsers role:integer
The migration will look like this:
class AddRoleToUsers < ActiveRecord::Migration
def change
add_column :users, :role, :integer
end
end
Add code to your User model to implement the Enum:
class User < ActiveRecord::Base
enum role: [:student, :parent, :teacher, :admin]
after_initialize :set_default_role, :if => :new_record?
def set_default_role
self.role ||= :student
end
end
You define the names of the roles, and if necessary, can change the names as needed (the integer values stored with each user record remain unchanged). Active Record will restrict the assignment of the attribute to a collection of predefined values, so you don’t have to add any code to restrict the names of the roles to a defined set. Best of all, enums come with a set of convenience methods that allow you to directly query the role without any extra code. For the enum attribute shown above, you can use these methods:
User.roles # => {"student"=>0, "parent"=>1, "teacher"=>2, "admin"=>1} # list all roles
user.student! # make a student user
user.student? # => true # query if the user is a student
user.role # => "student" # find out the user’s role
@users = User.student # obtain an array of all users who are students
user.role = 'foo' # ArgumentError: 'foo' is not a valid, we can’t set invalid roles
You can use the conditionals in a controller:
class UsersController < ApplicationController
def index
unless current_user.admin?
redirect_to :back, :alert => "Access denied."
end
@users = User.all
end
end
Or use it in a view:
<% if current_user.parent? %>
<li><%= link_to 'Grade Reports', some_path %></li>
<% end %>
In general, if access control adds a lot of code to a controller, you're well-advised to use CanCanCan or Pundit, because you can move the complex authorization logic into a central location segregated from the controllers ("skinny controllers"). However, if your needs are as simple as you describe, role-based authorization in the controller is optimal.
I've written a Rails Pundit tutorial that compares both approaches and provides greater detail on simple role-based authorization as well as role-based authorization with Pundit.
Upvotes: 40
Reputation: 221
Well, here is how I would implement it.
1) create Account model and add a polymorphic reference in its migration like this
class Account < ActiveRecord:Migration
def change
create_table :accounts do |t|
t.references :user, :polymorphic => true
t.column :name, :string
end
end
end
2) In each model class, for instance student class I would add the following line of code
class Student < ActiveRecord::Base
has_one :account, :as => :user
end
3) In Account model class
class Account < ActiveRecord::Base
belongs_to :user, :polymorphic => true
end
4) Use devise generator for Account model.
5) The big challenge is creating a new Student, basically you will be creating an Account record then assign this Account record to the newly created Student record.
a) There are 2 ways to do so: * Using nested forms. * Using a simple form and make the controller do the work.
I would encourage the second option, choose what fits you best and let me know if you have any problems.
Upvotes: 4
Reputation: 1170
If different app permissions is what you need, perhaps you want to assign roles to your users. This can be accomplished in many different ways. An easy one is to use Rolify gem: https://github.com/EppO/rolify
Upvotes: 1