使用Rolify定义角色

我正在尝试用Rails 4创建一个应用程序。

我正在考虑角色管理,并希望使用Rolify,因为它支持实例级角色分配。

对于其他同样问题的人来说,下面有两个非常好的答案(我只能打一个,但我同时使用了两个)。 查看下面的lorefnon和Cyb3rDud3答案)。 我还在搞清楚,但已经用数组(如lorefnon节目)和控制器/路由函数(如Cyb3rDud3所示)进行了迁移。

令我感到困惑的是,Rolify gem的所有文档都使用控制台来定义角色。

如何在代码中定义角色?

该板上的其他人提出了一些问题,这些问题暗示他们在db:seeds文件中定义了角色。 我不想这样做,因为我想控制谁使用我的种子文件比谁可以创建角色更紧密。

你在哪里做的?

所有示例都显示它是从控制台完成的。 我想定义一个角色列表,然后我想给角色权限(我想在这部分使用权威)。

我有一个用户模型。 我看到的另一个gem是角色模型。 它要求您在用户模型中创建角色数组。 它很明显你应该在Rolify中做到这一点 – 没有一个文件能给你这一步吗?

你在哪里定义角色?

令我感到困惑的是,Rolify gem的所有文档都使用控制台来定义角色。

Rolify文档不使用控制台来定义角色 – 它演示了如何在纯ruby中添加角色。 这非常强大,因为您可以在运行ruby时定义角色。 您不限于某些配置文件或某些数据库表中定义的静态角色列表。


您需要问的第一个问题是何时创建角色?

最常见的用例分为两组:

1.角色是静态的。

应用程序安装/部署期间应用程序开发人员,支持人员或公司高管创建一次角色,并且在正在运行的应用程序的生命周期中,这些预先创建的角色将分配给不同的用户。

此类角色的最常见用例包括对公司中人员的建模(开发人员,经理,支持等)进行建模,或对先前已知职责进行建模(编辑,管理员,查看者等)

如果您的角色确实属于这样的用例,那么接下来您必须决定 – 其职责是创建和修改角色。 通常有两种可能性:

1.1。 应用程序开发人员本身就是必须添加/删除/修改角色的人。 在这种情况下,最好依赖种子数据或Rails迁移。

迁移的优点是,如果需要,您可以轻松地回滚数据。 此迁移是rolify生成器生成的迁移的补充,它为您创建角色相关表的模式(请参阅下图)。

这样的迁移可能如下所示:

分贝/迁移/ 20151204083556_create_application_roles.rb

class CreateApplicationRoles < ActiveRecord::Migration def up ['admin', 'support', 'editor'].each do |role_name| Role.create! name: role_name end end def down Role.where(name: ['admin', 'support', 'editor']).destroy_all end end 

有些人正确地认为它是一个反模式,可以通过迁移来管理模式更改和数据更改。 data-migrate是一个gem,允许您将以数据为中心的迁移与模式迁移分开。

在这种情况下,实际角色分配的所有其他情况将基于用户操作或应用程序事件通过add_role提供的add_role或remove_role方法发生。这将在运行应用程序的生命周期过程中发生,而不是在应用程序安装期间发生。

1.2添加/删除/修改角色的任务由支持团队或技术主管完成。 在这种情况下,需要提供管理角色的管理界面。

在这种情况下,您将拥有一个rails控制器来管理角色。 创建操作将用于创建角色,show action将用于显示角色等。这些操作将具有附带的视图,这些视图将为最终用户提供图形用户界面以管理角色。

2.角色是动态的

此类别涵盖角色被视为更类似于类别或标记并且可由最终用户创建/修改/删除的用例。 例如,图书馆员可以为特定类型的书籍分配一些角色/类别。

这种情况类似于1.2,因为您必须通过rails控制器处理创建/删除/更新角色。


下一部分是如何在表格中构建信息。

Rolify期望一个特定的模式(在某种程度上可自定义),但预期的模式足够灵活,可以处理所有上述用例。

滚动表格

我真的只是经历了同样的过程,就像@ user2860931一样,我只能找到一些关于如何从控制台分配角色的例子。 我需要的是一种以编程方式灵活的方式来管理具有管理角色的用户或具有pmo角色的用户如何将这些角色分配给其他人。

通过一些实验,这就是我为我解决的问题。 在这个例子中,我使用Devise进行身份validation,使用Rolify进行角色validation。

我假设您已经安装并运行了Devise,因此您拥有现有的用户模型。 按照gem页面上的说明安装Rolify。 我使用了角色模型的建议名称Role。 所以如此处所述: https : //github.com/RolifyCommunity/rolify 。 安装GEM,使用rolify角色用户生成。 并迁移数据库迁移。

这将有效地为您留下一个新的表Roles和与Users表的has_and_belongs_to_many关系。

至于我的目的,我不需要角色的通常创建读取(显示)更新删除(CRUD)界面,我刚刚通过seeds.rb创建了一些这样的。

 #Seeding the Role table # p "Removing existing #{Role.all.count} roles" Role.destroy_all p "Creating 7 roles" [:user, :admin, :portfolio_manager, :programme_manager, :project_manager, :coordinator, :pmo].each do |role| Role.create( name: role ) end p "Should have created 7 Roles, roles created: #{Role.all.count}" 

我和开发人员一样留下了我的额外评论,所以我一眼就看出它工作得很好。 所以,当你跑步

rake db:seed

你将有一些角色设置。 或者,您可以通常的方式创建角色控制器和视图,以允许具有管理角色的用户添加新角色。

现在有趣的一点可以开始了。 到目前为止,Devise已经完成了有关您用户的所有事情,或者您可能已经完成了自己的控制器,但您需要创建自己的用户控制器和视图。 因为我只想要一个针对每个用户的角色的复选框列表,我已经完成了如下操作。 这是我的

 users_controller.rb class UsersController < ApplicationController before_action :set_user, only: [:show, :edit, :update] def index @users = User.all end def show end def edit end def update respond_to do |format| if @user.update(user_params) # TODO: Move hardcode flash message into language file format.html { redirect_to @user, notice: 'User was successfully updated.'} format.json { render :show, status: :ok, location: @user } else format.html { render :edit } format.json { render json: @user.errors, status: :unprocessable_entity } end end end private def set_user @user = User.find(params[:id]) end def user_params params.require(:user).permit(:username, :email, {role_ids: []}) end end 

现在你必须为这些路线定义这些路线,使它们不与Devise路线发生冲突。 我现在保持简单,并且资源化所有通常的路线来强化你的应用程序你可能想要改变它并且只允许那些你实际拥有的路线。

 routes.rb Rails.appliction.routes.draw do devise_for :users root 'pages#home' resources :users #must be after devise end 

当您现在执行rake路由时,您将获得应用程序的通常路径以使控制器工作。 像这样按顺序:

  Prefix Verb URI Pattern Controller#Action new_user_session GET /users/sign_in(.:format) devise/sessions#new user_session POST /users/sign_in(.:format) devise/sessions#create destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy user_password POST /users/password(.:format) devise/passwords#create new_user_password GET /users/password/new(.:format) devise/passwords#new edit_user_password GET /users/password/edit(.:format) devise/passwords#edit PATCH /users/password(.:format) devise/passwords#update PUT /users/password(.:format) devise/passwords#update cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel user_registration POST /users(.:format) devise/registrations#create new_user_registration GET /users/sign_up(.:format) devise/registrations#new edit_user_registration GET /users/edit(.:format) devise/registrations#edit PATCH /users(.:format) devise/registrations#update PUT /users(.:format) devise/registrations#update DELETE /users(.:format) devise/registrations#destroy user_unlock POST /users/unlock(.:format) devise/unlocks#create new_user_unlock GET /users/unlock/new(.:format) devise/unlocks#new GET /users/unlock(.:format) devise/unlocks#show root GET / pages#home about GET /about(.:format) pages#about contact GET /contact(.:format) pages#about users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit user GET /users/:id(.:format) users#show PATCH /users/:id(.:format) users#update PUT /users/:id(.:format) users#update DELETE /users/:id(.:format) users#destroy 

现在剩下要做的就是构建用户界面,这对我来说是最重要的部分,如果我也正确理解你的话。 为了快速构建这个,我的例子并没有很好地展示出完整的css魔法,但我相信你可以根据自己的喜好来做到这一点。

因此,要显示现有用户并选择列表,请在/ app / views / users文件夹中创建index.html.erb。 创建一个简单的show.html.erb和一个编辑,您可以在其中分配和删除现有角色。 像这样。

 index.html.erb   <% @users.each do |user| %> 

<%= link_to "#{user.username}<#{user.email}>", user %> <%= link_to "edit", edit_user_path(user) %>

<% end %> show.html.erb

Username: <%= @user.username %>

Email address: <%= @user.email %>

<%= link_to "Back", users_path %> edit.html.erb

Username: <%= @user.username %>

Email address: <%= @user.email %>

<%= form_for @user do |f| %> <% Role.all.each do |role| %> <%= check_box_tag "user[role_ids][]", role.id, @user.role_ids.include?(role.id) %> <%= role.name %> <% end %> <%= f.submit %> <% end %> <%= link_to "Back", users_path %>

你有它,一个简单的用户界面,列出数据库中的所有可用角色,并提供针对用户记录的勾选框,以启用或禁用此类角色。 像这样:

用户记录和角色选择列表的示例

对我来说这对我来说也是一个小问题,但希望这会让你的方式增加逻辑和用户体验。

在阅读了项目页面中的文档和示例后,我决定不使用gem来管理我页面中的角色,因为我认为这需要花费大量时间来配置和使用。 所以相反,我做了以下,(我相信你使用了设计用于您的用户模型,即使它不是强制性的):

如果您想要定义某些角色并且“静态”不可修改但可从您的页面分配,请参见下文,如果没有跳转到下一个粗线

  1. 使用迁移将名为role: integer的字段添加到User模型。 (我们使用整数,因为这个值将与我们在下一步中定义的枚举中的一个条目相关联)
  2. 在您的文件user.rb (模型)中,添加如下的enum

     class User < ActiveRecord::Base devise :registerable, #... enum role: [:admin, :normal, :premium, :moreRolesHere ] after_initialize :set_default_role, :if => :new_record? def set_default_role self.role ||= :normal end end 
  3. 然后,在任何控制器或视图或def您只需要获取当前用户或您想要分配角色的任何用户,并按照下面的行进行操作:

     #let's suppose we want to make premium the current user current_user.premium! #or someone else to be admin user = User.first user.admin! 
  4. 然后,您可以在您正在处理的任何页面或控制器中进行自己的validation,只需询问用户的角色:

     #see if the current user is admin if current_user.role == "admin" #do some admin stuff end 

如果要在页面中添加,修改和删除角色,还要在其中分配角色

首先,在直接从页面分配角色时要小心。 这里的问题是每个人都能够在一个领域中为自己分配自己的角色。 但如果这是您所需要的,请执行以下操作:

  1. 创建一个名为Role的模型,其字段为role: string
  2. 创建与该模型关联的控制器roles_controller.rb
  3. 创建所需的视图以显示与角色管理相关的操作(创建,编辑,删除),请注意此页面必须仅供登录用户使用 。 为用户选择或添加角色,您将在用户控制器或所需的任何其他控制器中进行管理。
  4. 在任何其他视图中,您想要询问用户的角色,您需要访问角色表并检索与用户对应的角色。 users表将需要一个列role_ids: text (它的文本因为你需要在那里保存多个角色,所有角色都包含在一个数组中),这将代表他的角色。 在你的user.rb模型中,你可以使用get_roles和其他def方法在控制器和视图中使用更清晰的代码:

     class User < ActiveRecord::Base devise :registerable, #... serialize :role_ids #will return you an array of roles-(strings) of the user def get_roles roles = [] role_ids.each do |role_id| roles << Role.find(role_id).role end return roles end #ask if this user has some role-(string) def has_role(role) roles = get_roles return roles.include?(role) end end 
  5. 最后,当然您需要为角色实现控制器,创建,更新和销毁以及与其视图关联的所有def

您可以看看如何在数据库中保存数组,序列化

这种方法不使用与市场中的角色管理或授权相关的任何gem: pundit , cancan , rolify 。 如果你对我的方法持怀疑态度,想要弄清楚你的手,请留下一些链接。