我一直在尝试为我的组织开发人力资源管理系统,并创建了基本的基础设施。 我现在到了需要创建管理员授权的地步。 我的组织非常树状结构,从我所掌握的,我想做的事情在一些管理员宝石(例如活动管理员)中并没有真正促进(尽管如果我错了,请纠正我! 我已经考虑过为下面的每个级别使用parent_id
字段,但不确定如何在应用程序中促进这一点。
实际上,我希望最低级别的员工能够查看他们的大部分个人数据,但不包括一些类别,如绩效报告/注释和类似属性,并能够编辑基本详细信息,如联系方式,以确保它们是最新的。 然后,他们的直线经理应该能够查看他们负责的员工的所有详细信息。 该组织大约有四个层次,尽管我想保持它的可扩展性。 第二层和第三层还有多个直线经理,我认为这就是宝石问题出现的地方。
我已经安装了祖先宝石,因为我认为这将是解开困境的关键,但想知道是否有人有任何好主意。 我目前的employee.rb
文件在下面,只是不知道从这里开始。
class EmployeesController < ApplicationController
before_action :set_employee, only: [:show, :edit, :update, :destroy]
before_action :logged_in_employee, only: [:index, :show, :edit, :update, :destroy]
before_action :correct_employee, only: [:show, :edit, :update]
before_action :admin_employee, only: :destroy
# GET /employees
# GET /employees.json
def index
@employees = Employee.paginate(page: params[:page])
end
# GET /employees/1
# GET /employees/1.json
def show
end
# GET /employees/new
def new
@s3_direct_post = S3_BUCKET.presigned_post(key: "uploads/#{SecureRandom.uuid}/${filename}", success_action_status: 201, acl: :public_read)
@employee = Employee.new
end
# GET /employees/1/edit
def edit
@employee = Employee.find(params[:id])
end
# POST /employees
# POST /employees.json
def create
@employee = Employee.new(employee_params)
if @employee.save
@employee.send_activation_email
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
# PATCH/PUT /employees/1
# PATCH/PUT /employees/1.json
def update
respond_to do |format|
if @employee.update(employee_params)
flash[:success] = "Profile updated"
format.html { redirect_to @employee, notice: 'Employee was successfully updated.' }
format.json { render :show, status: :ok, location: @employee }
else
format.html { render :edit }
format.json { render json: @employee.errors, status: :unprocessable_entity }
end
end
end
# DELETE /employees/1
# DELETE /employees/1.json
def destroy
Employee.find(params[:id]).destroy
flash[:success] = "Employee deleted"
respond_to do |format|
format.html { redirect_to employees_url, notice: 'Employee was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_employee
@employee = Employee.find(params[:id])
end
# Confirms a logged-in user.
def logged_in_employee
unless logged_in?
store_location
flash[:danger] = "Please log in."
redirect_to login_url
end
end
# Confirms the correct user.
def correct_employee
@employee = Employee.find(params[:id])
redirect_to(root_url) unless current_employee?(@employee)
end
# Confirms an admin user.
def admin_employee
redirect_to(root_url) unless current_employee.admin?
end
# Never trust parameters from the scary internet, only allow the white list through.
def employee_params
params.require(:employee).permit(:avatar, :email, :first_name, :last_name, :service_no, :password, :date_of_birth, :gender, :service_start_date, :substantive_rank, :promotion_date, :passport_number, :passport_expiry, :passport_country_of_origin, :nationality, :national_insurance)
end
end
在 ActiveAdmin 中,当您访问资源(或集合)时,就会发生授权。它基本上使用操作名称(例如index
,show
,edit
,update
等)和模型对象或类,具体取决于可用于授权请求的内容。如果没有配置,ActiveAdmin 不提供授权解决方案。如果您不配置任何内容,则只会让任何用户执行任何操作。
ActiveAdmin的授权方法与cancancan宝石(或者更确切地说是它的继任者cangem)非常有效,但Pundit也开箱即用。滚动自己的适配器也非常简单:您可以毫不费力地使用任何 gem。
对于您的特定问题:
员工之间的关系以及您如何进行授权不一定必须相互影响。基于角色的方法似乎可以很好地解决您的问题。例如,您可以为不同的层次结构级别创建角色:
- 员工(最低级别)
- 直线经理
- 直线经理的老板
- 管理员(超级用户,可以做任何事情)
用户可以有多个角色,也可以是包容性角色(直线经理可以执行员工可以执行的所有操作)。据我了解,后者更适合您的问题。
对于某人想要更新用户联系信息(不一定是她自己的联系信息)的具体情况,您必须检查用户的角色是否允许更新操作,以及当前用户是否有权访问其他用户对象。如果是员工,必须是她自己,但直线经理也可以更新下属的联系信息。
大多数授权库都提供了一种声明性的方式来表达不同角色可以执行的操作。我鼓励你看看康康舞宝石。