ruby-on-rails - 实现多个用户角色

标签 ruby-on-rails

我使用 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_rolehas_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/

相关文章:

ruby-on-rails - 通过 users_controller.rb 中的代码修改用户的数据库

ruby-on-rails - 如何将任何 HTTParty.get 响应转换为 UTF-8

SQL 按喜欢排序

javascript - Rails 应用程序中日期范围选择器的国际化

ruby-on-rails - 验证多列的 allow_blank

ruby-on-rails - 依赖销毁不起作用,has_many :model, :dependent => :destroy

ruby-on-rails - 在 Windows 上启动 Rails 服务器时出错

mysql - 创建餐厅菜单时我应该使用 has_many through 还是 habtm 关联?

ruby-on-rails - 忘记密码设计 gem API

ruby-on-rails - 需要一种较少重复的方式在 Mac 上为菜鸟启动 Rails