我使用 state_machine 取得了巨大的成功,并且喜欢它通过几行代码动态创建的类方法。
但是,我不确定如何继续我正在创建的系统。我目前正在开发一个用户具有多种角色的系统。因此,拥有一个状态为 的用户并不简单。未经证实至确认然后可能到管理员 .
一个用户现在有很多角色,可以是 潜力 , 一个 骑自行车的人 , 一个 协调员 , 一个 经理 , 一个 论坛管理员 , 一个 店铺管理员 , 一个 super 管理员 和 筹款事件 .
所以层次结构是这样的:
superadmin
forum admin, store admin
cyclist, coordinator, manger, fundraiser
potential
但是,一台状态机不会在这里解决问题,因为一个用户完全有可能同时拥有上述所有角色。
我正在实现自己的类方法,以在某种程度上模拟状态机:
class User < ActiveModel::Base
has_many :jobs
has_many :roles, through: :jobs
def role_array
self.roles.pluck(:role)
end
def has_role?(role)
role_array.include?(role)
end
# checking
def is_superadmin?
role_array.include?('superadmin')
end
# changing
def add_role(role)
self.update_attributes(accepted_at: Time.now) if self.is_only_potential?
self.user_roles.create(role_id: Role.find_by(role: role).id ) if !self.has_role?(role)
end
def remove_role(role)
self.user_roles.find_by( role_id: Role.find_by(role: role).id ).destroy if self.has_role?(role)
end
def make_superadmin!
add_role('superadmin')
end
def denounce_superadmin!
remove_role('superadmin')
end
end
这只是一个小问题。所以我的问题是:
1) 我做对了吗?您将如何处理具有多个角色的用户?
2) 即使我做得对,我想创建一个 state_machine-esque DSL,所以当我需要创建一个新角色时,比如说“运行者”,我可以在我的模型中做这样的事情:
class User < ActiveModel::Base
has_many :jobs
has_many :roles, through: :jobs
multiroles initial: :potential do
roles [:superadmin, :forum_admin, :store_admin, :cyclist, :coordinator, :manager, :fundraiser, :potential]
# dynamically creates the above methods for getting and setting for all roles
end
我应该如何创建该多角色方法?内部
lib
?准备好作为我的第一颗 gem 打包了吗?我不知道如何动态创建方法,但我想开始:)
只是一个想法,也许
multiroles
方法可以通过Roles.all
动态获取所有角色并自动添加上述方法!甚至可以照顾 has_many :jobs
has_many :roles, through: :jobs
另外,我应该如何验证这些角色?我目前正在我的 Controller 中的 before block 中执行此操作:
def only_superadmins
redirect_to root_url if !current_user.has_role?('superadmin')
end
我的应用程序 Controller 中也有很多这些方法,
only_superadmins
, only_cyclists
等,我通过 before_method
给他们打电话各种子 Controller 中的方法。这个可以吗?我应该使用cancan还是什么?
如果我做得对,我想知道如何使用我的 Gem 动态创建这些方法。我在想一些事情:
class panel_controller < ApplicationController
allowed_roles [:super_admin, :forum_admin, :store_admin]
end
并且 allowed_roles 方法将创建这些方法
def allowed_roles(role_array)
role_array.each do |role|
define "only_#{role.to_s}s" do |arg|
redirect_to root_url if !current_user.has_role?(arg.to_s)
end
end
end
所以这将以编程方式创建这些方法:
def only_super_admins
redirect_to root_url if !current_user.has_role?('super_admin')
end
def only_forum_admins
redirect_to root_url if !current_user.has_role?('forum_admin')
end
def only_store_admins
redirect_to root_url if !current_user.has_role?('store_admin')
end
虽然我不明白为什么这不起作用,但这并没有让我觉得效率太高。
也许
allowed_roles
应该是这样的:def allowed_roles(wanted_roles)
redirect_to root_url unless (current_user.role_array & wanted_roles).empty? # it's ONLY empty when any of the current_user roles exists in the wanted_roles array
end
我只是想要一些指针真的:)
如何创建 gem 来制作
allowed_roles
Controller 和 multiroles
可用的方法可用于用户模型? 可以
cancan
像这样管理多个角色?我应该只使用它吗?
最佳答案
恢复答案:
为了处理模型的角色,一个不错的选择是使用 gem rolify .有了它,您可以轻松定义任意数量的角色,并将任意数量的角色关联到您的用户。使用简单,按照官方文档here .
CanCan (或其继承者 CanCanCan )用于处理权限。您将在文件 app/models/ability.rb
中定义具有每个角色(使用 rolify 定义)的用户有权执行的操作。 .然后,在 Controller 或 View 中,您只需验证用户是否有权对资源执行操作。例如,在您的 Controller 中,您可以验证 @comment = Comment.new(params); authorize! :create, @comment
之类的授权。 ,并且在您看来,您可以验证 if can? :create, Comment
之类的授权.引用官方文档here用于学习如何设置和使用 CanCan。
将这些应用于您的具体问题:
将 Rolify ( gem "rolify"
) 和 CanCan ( gem "cancan"
) gem 添加到您的 Gemfile。
执行 rails shell 命令 rails g rolify Role User
创建一个名为 Role 的新类(或使用您喜欢的名称)并在现有类 User 中添加一些类方法。由于新类 Role 将向您的数据库添加表 Role,您必须运行 rake db:migrate
(使用 ActiveRecord 时)。
添加 resourcify
到用户将访问的任何类。例如:
class Forum < ActiveRecord::Base
resourcify
end
完成这些步骤后,您的 User 类将配备方法
add_role
, remove_role
和 has_role
您可以使用它们添加任意数量的角色:user.add_role :superadmin
user.add_role :fundraiser
user.has_role? :superadmin
# >> true
user.has_role? :fundraiser
# >> true
您甚至可以将角色限定为一个资源或实例:
user.add_role :cyclist, Forum
user.add_role :coordinator, Forum.first
user.has_role? :cyclist, Forum
# >> true
user.has_role? :cyclist, Store
# >> false
user.has_role? :coordinator, Forum.first
# >> true
user.has_role? :coordinator, Forum.second
# >> false
所以你可以这样写你的用户类:
class User < ActiveModel::Base
rolify
has_many :jobs
# checking
def is_superadmin?
self.has_role?('superadmin')
end
# changing
def add_new_role(role)
self.update_attributes(accepted_at: Time.now) if self.is_only_potential?
self.add_role(role)
end
def make_superadmin!
add_new_role('superadmin')
end
def denounce_superadmin!
remove_role('superadmin')
end
end
要验证这些角色,您可以使用 CanCan。执行 rails shell 命令
rails g cancan:ability
生成文件app/models/ability.rb
您将在其中定义角色的权限。class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.has_role? :superadmin
can :manage, All # can manage (Read, Create, Update, Destroy, ...) everything
elsif user.has_role? :forum_admin
can :manage, Forum # can manage (Read, Create, Update, Destroy, ...) any Forum
elsif user.has_role? :store_admin
can :manage, Store do |store| # Can manage only its own store
store.try(:user) == user
end
elsif user.has_role? :forum_member
can :create, Post do |post|
if post.forum.members.include? user
true
end
end
can :destroy, Post do |post|
post.try(:user) == user
end
can :update, Post do |post|
post.try(:user) == user
end
elsif ...
else # Users without role
can :read, All
end
end
end
在您的 Controller 中,您可以调用
authorize!
方法。例如:# app/controllers/posts_controller.rb
def create
@post = Post.new(params[:post])
@post.user = current_user
authorize! :create, @post
if @post.save
redirect_to @post
else
render :action => 'new'
end
end
或者您可以在 Controller 开始时包含 faloowing,并且在每个操作之前自动加载和授权(或不授权)资源:
class PostController < ApplicationController
load_and_authorize_resource :post
...
def create
authorize! :create, @post
if @post.save
redirect_to @post
else
render :action => 'new'
end
end
在 观看本教程RailsCast 开始使用 CanCan。
我希望这可以帮助指导您解决问题。
关于ruby-on-rails - 实现多个用户角色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23585871/