我应该如何在Rails应用程序中构造两种类型的角色?

时间:2017-03-15 22:09:40

标签: ruby-on-rails activerecord

我正在开发一个Ruby on Rails应用程序,它有两种"角色"。

  • 一个用户将拥有多个角色,例如" Admin"," Team Lead"等等,这些将在种子文件中定义,而不是由用户生成
  • 另一个将由用户生成并分配给其他用户,例如" Chef"," Waiter"等。

它们都相似,因为它们只有name列。前者将与CanCanCan等授权工具一起使用。我目前计划允许用户和角色使用has_many :through关系来支持其他许多人。

class Role
  has_many :user_roles
  has_many :users, through: :user_roles
end

class User
  has_many :user_roles
  has_many :roles, through: :user_roles
end

class UserRole
  belongs_to :user
  belongs_to :role
end

我的问题是:

  • 后者("厨师","服务员"等)是否应该放在同一张桌子上?单独的表?
  • 我应该使用某种继承吗?
  • 这种情况的好习惯是什么?

我计划使用术语"角色"在后者的用户界面中,显示了什么"角色"用户有。前者我想更多的是他们在应用程序中拥有什么特权。

5 个答案:

答案 0 :(得分:2)

如果你离开角色和身份验证的技术方面,并尝试用更加面向业务的方法来描述“事物”,那么你就可以让自己更加清晰。

我的理解是:您对应用程序的用户有一个定义,用于描述该用户具有的授权,例如: “管理员”拥有的权利多于“编辑”或“社区管理者”。

您还希望应用程序的这些用户能够创建与(其他?)用户关联的名称。正如我所理解的,这些名称与授权无关。 也许这些名称更像是标签,人们可以分配? 我会将两者分开,因为它不应该让用户创建角色或修改现有角色,这可以授予他们访问管理功能的权限。

如果你想看一个标记宝石,我可以推荐这个:https://github.com/mbleigh/acts-as-taggable-on我用了好几年了,虽然有它的缺点,但它很可靠。

答案 1 :(得分:1)

我建议在推出自己的解决方案之前先看一下rolify,因为它会解决你以后需要重新实现/发现的一些事情(例如角色查询,避免N + 1查询等) )。它还与can?很好地集成,并且应该适用于您的问题的授权部分。

虽然允许用户创建新角色并不是不可能的(通过在Role.create之上投掷输入表单),但这开始变得混乱,因为您需要跟踪哪些用于授权以及哪些用于提供信息(和用户创建)。

由于这两组事物是出于不同的目的,我完全同意this other answer分离用户生成的实体更清晰,并希望将它们实现为标记。您可以在某些视图中一起显示所有“角色”,但这并不意味着将它们存储在单个表中是有意义的。

旁注:如果您最终推出自己的解决方案,请考虑在此处使用HABTM。仍将创建连接表,但您不必管理连接表模型。 E.g。

has_and_belongs_to_many :users, join_table: :users_roles

答案 2 :(得分:0)

由于您只有有限数量的角色,因此可以使用位掩码并将其直接存储在用户模型上作为简单整数。

有关详细信息,请参阅此Railscasts。这将是最有效的数据库和关联方式,尽管这可能不是最简单的理解。唯一真正的限制是你不能改变你检查的值数组,只能附加到它。

祝你好运!

答案 3 :(得分:0)

我会创建另一个模型Permission,您可以在其中创建要在任何给定角色下管理的所有权限的列表。

然后在权限和角色之间有多对多。

从UserRole实例,您将能够列出权限,并且将来您可以为角色添加其他权限,只需在几个表中运行插入

角色:Onwer,厨师,厨师,服务员 权限:can_cook,can_buy_wine,can_manage,can_charge_custome

所有者:can_manage,can_buy_wine,can_charge_customer 厨师:can_cook,can_manage 服务员:can_charge_customer

这将是一个良好的开端,您可以根据自己的需求将角色功能发展为没有外部依赖关系。

答案 4 :(得分:0)

此外,您可以只使用Users表并将role列添加为整数,并为它们提供默认0整数的角色代码。

#app/helpers/roles_helper.rb

module RolesHelper
  @roles = {
    'Default' => 0,
    'Waiter' => 10,
    'Chef' => 20,
    'Superadmin' => 30
  }

class << self

  def list_roles
    @roles.map{|k,v| [k,v] }
  end

  def code(str)
    return @roles[str]
  end

  def value(id)
    return @roles.key(id)
  end
end

  def require_default_users
    unless current_user && current_user.role >= RolesHelper.code('Waiter')
      redirect_to root_url(host: request.domain)
    end
  end

  def require_superadmin_users
    unless current_user && current_user.role >= RolesHelper.code('Superadmin')
      redirect_to courses_path
    end
  end
end

在控制器中访问

样品:

class Admin::AdminController < ApplicationController
 include RolesHelper


  def sample_action_method
    require_default_users #if non admin user redirect ...

    puts "All Roles: #{RolesHelper.list_roles}"
    puts "Value: #{RolesHelper.value(30)}"
    puts "Code: #{RolesHelper.code('Superuser')}"
  end
end