Reputation: 63
I'm building a job board application. I'm new to programming and am teaching myself the rails framework.
I'm using Devise for authentication. I will have two different types of users; Job Seeker
and Employer
. The job seeker will create a profile and search for job postings and the employer will create a company profile and post job listings. In the future, the employer will also be able to search for employees based on qualifications, experience, education, etc. but for now I'm just building my MVP.
Upvotes: 2
Views: 2104
Reputation: 76774
This type of functionality is tricky, namely because you have to put functionality before implementation (IE most people get hung up about Devise
, whereas it might not feature at all)
You have two ways:
- Roles (authorization)
- Multiple models (authentication)
Devise is an authentication system (user logged in); you may be better using authorization (can user do x or y). Authorization is out of Devise's scope.
Whilst you could use multiple models (Devise), I think it creates too much unnecessary bloat for what you need.
Instead, I would use a very simple role system (using enum
):
#app/models/user.rb
class User < ActiveRecord::Base
enum role: [:job_seeker, :employer]
has_one :profile
before_create :build_profile
has_many :applications
has_many :listings, through: :applications
end
#app/models/application.rb
class Application < ActiveRecord::Base
belongs_to :listing
belongs_to :user
end
#app/models/listing.rb
class Listing < ActiveRecord::Base
has_many :applications
has_many :applicants, through: :applications, class_name: "User", foreign_key: :user_id
end
You'll need to add a role
column (int
) to your users
table. You'll create the default role by using a default: [x]
switch when creating your column:
def change
add_column :users, :role, :integer, default: 0 #-> defaults to job seeker
end
--
You've described several factors which would lend themselves perfectly to this:
Job seeker
will create a profileEmployer
will create a profile and post listings
... all meaning your "flow" will remain similar for both user types. You'd just have to manage what each user can do with authorization.
#config/routes.rb
resource :profile, controller: :users, only: [:show, :update] #-> url.com/profile
resources :listings, only: [:show] do
post :apply, on: :member #-> url.com/listings/:id/apply
end
resources :companies, controller: :users, only: [:show]
#app/controllers/users_controller.rb
class UsersController < ApplicationController
#show will automatically be loaded
def update
current_user.update profile_params
end
private
def profile_params
params.require(:user).permit(profile_attributes: [:name, :etc, :etc])
end
end
#app/views/users/show.html.erb
<%= form_for current_user do |f| %>
<%= f.fields_for :profile do |p|
<% if current_user.job_seeker? %>
<%= f.text_field :name, placeholder: "Your name" %>
<% elsif current_user.employer? %>
<%= f.text_field :name, placeholder: "Company name" %>
<% end %>
<% end %>
<%= f.submit %>
<% end %>
You'd then be able to use the following to check whether a user can create listings, or just view:
#app/controllers/listings_controller.rb
class ListingsController < ApplicationController
before_action :check_seeker, only: [:apply]
before_action :check_employer, only: [:new, :create, :destroy]
def new #-> employers
@listing = current_user.listings.new
end
def apply #-> job seekers
@listing = Listing.find params[:id]
@application = current_user.applications.new
@application.listing = @listing
redirect_to @listing, notice: "Application successful!" if @application.save
end
private
def check_seeker
redirect_to listings_path, notice: "Only Job Seekers Allowed" unless current_user.job_seeker?
end
def check_employer
redirect_to root_url, notice: "Only Employers Allowed" unless current_user.employer?
end
end
Hopefully this gives you the gist.
To get Devise working with your new column, you'll need to extend the Devise Sanitizer:
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :role
end
end
This will allow you to change the role
field on signup:
#app/views/devise/registrations/new.html.erb
.....
<%= f.select :role, User.roles %>
Upvotes: 5
Reputation: 3231
For roles you can use CanCanCan
gem and RoleModel
gem with devise
which will be better for user with different roles.
Defining abilities using cancancan
Example for user roles with above gems..
Upvotes: 1
Reputation: 26802
Devise is good for authentication but for role and access control you may want to look into Rolify: https://github.com/RolifyCommunity/rolify.
This will allow you to keep a single user model and control access to different features with Role queries, ie:
unless current_user.has_role?(:admin)
redirect_to ...
else
render ...
end
Upvotes: 2