基于部门的 Rails CanCanCan 资源能力

Posted

技术标签:

【中文标题】基于部门的 Rails CanCanCan 资源能力【英文标题】:Rails CanCanCan resource abilities based on department 【发布时间】:2019-06-28 13:31:44 【问题描述】:

我有两种用户类型 AdminNormal User

我有以下部门

前台(例如,id 为 1) 后台(例如,id 为 2) 管理员(例如,id 为 3)

我有一个名为 Entry 的模型,它采用 user_id、department_id、customer_id

管理员用户对所有部门和所有条目

完全控制CRUD

普通用户是为各个部门创建的,并且 CRU 可以控制各个部门的条目

当我从 普通用户(例如,id 为 2)帐户创建 条目 时,我得到了正确的 customer_id、department_id、user_id 集 em> 在表中。此用户的权限只有一个条目 can_create_entry(current_user.id, customer_id, department_id) 例如,(1, 1, 2) 用于前台普通用户帐户。

当我从 Admin(例如,id 为 1)帐户创建 entry 时,我得到 customer_id、department_id、user_id 为 (1,1,1)在表中,我尝试为 id 为 2 的后台部门创建一个条目。

当我检查 Admin 用户的能力列表时;我发现条目能力有重复项,即,

#<CanCan::Rule:0x0000000b61fd18 @match_all=false, @base_behavior=true, @actions=[:create], @subjects=[Entry(Table doesn't exist)], @conditions=:user_id=>1, :customer_id=>2, :department_id=>1, @block=nil>

#<CanCan::Rule:0x0000000b61fd18 @match_all=false, @base_behavior=true, @actions=[:create], @subjects=[Entry(Table doesn't exist)], @conditions=:user_id=>1, :customer_id=>2, :department_id=>2, @block=nil>

#<CanCan::Rule:0x0000000b61fd18 @match_all=false, @base_behavior=true, @actions=[:create], @subjects=[Entry(Table doesn't exist)], @conditions=:user_id=>1, :customer_id=>2, :department_id=>3, @block=nil>

对于普通用户我只有一个条目

#<CanCan::Rule:0x0000000b61fd18 @match_all=false, @base_behavior=true, @actions=[:create], @subjects=[Entry(Table doesn't exist)], @conditions=:user_id=>2, :customer_id=>2, :department_id=>1, @block=nil>

请帮我解决管理员角色的问题。

已编辑: ability_base.rb

class AbilityBase
  include CanCan::Ability
  ...
  def can_read_entries(customer_id, department_id)
    can :read, Entry, :customer_id => customer_id, :department_id => department_id
  end

  def can_create_entries(customer_id, department_id,user_id)
    can :create, Entry, :customer_id => customer_id, :department_id => department_id, :user_id => user_id
  end

  def can_update_entries(customer_id, department_id, user_id)
    can :update, Entry, :customer_id => customer_id, :department_id => department_id, :user_id => user_id
  end

  def can_destroy_entries(customer_id, department_id)
    can :destroy, Entry, :customer_id => customer_id, :department_id => department_id
  end
  ...
end

user_ability.rb

class UserAbility < AbilityBase
  def initialize(current_user)
    if current_user
       user_department_type_names = 
       @customer = current_user.customer
       @user_type = current_user.user_type
       current_user_dept = current_user.departments           
       @user_department_ids = current_user_dept.collect(&:id)
       @user_department_type_ids = current_user_dept.collect  |dept| 
          dept_type = dept.department_type
          user_department_type_names["#dept_type.type_name"] = dept.id
          dept_type.id
       
       ...
       if user_department_type_names.has_key?("FRONT_OFFICE")
         dept_id = user_department_type_names["FRONT_OFFICE"]
         if @user_type == "NORMAL_USER"
            can_read_entries(customer.id, dept_id)
            can_create_entries(customer.id, dept_id, user_id)
            can_update_entries(customer.id, dept_id, user_id)
         elsif @user_type == "ADMIN"
            can_read_entries(customer.id, dept_id)
            can_create_entries(customer.id, dept_id, user_id)
            can_update_entries(customer.id, dept_id, user_id)
            can_destroy_entries(customer.id, dept_id)
         end
       elsif user_department_type_names.has_key?("BACK_OFFICE")
         dept_id = user_department_type_names["BACK_OFFICE"]
         if @user_type == "NORMAL_USER"
            can_read_entries(customer.id, dept_id)
            can_create_entries(customer.id, dept_id, user_id)
            can_update_entries(customer.id, dept_id, user_id)
         elsif @user_type == "ADMIN"
            can_read_entries(customer.id, dept_id)
            can_create_entries(customer.id, dept_id, user_id)
            can_update_entries(customer.id, dept_id, user_id)
            can_destroy_entries(customer.id, dept_id)
         end
       elsif user_department_type_names.has_key?("ADMIN")
         dept_id = user_department_type_names["ADMIN"]
         if @user_type == "NORMAL_USER"
            can_read_entries(customer.id, dept_id)
            can_create_entries(customer.id, dept_id, user_id)
            can_update_entries(customer.id, dept_id, user_id)
         elsif @user_type == "ADMIN"
            can_read_entries(customer.id, dept_id)
            can_create_entries(customer.id, dept_id, user_id)
            can_update_entries(customer.id, dept_id, user_id)
            can_destroy_entries(customer.id, dept_id)
         end
       end
       ...
    end
  end
end

【问题讨论】:

您的 userability.rb 文件在哪里?将其添加到问题中 已相应编辑 【参考方案1】:

我为此使用了一些不同的方法:

class UserAbility
  include CanCan::Ability

attr_accessor :user

def initialize(user)

@user = user

can :read, Entry, do |entry|
  is_admin || (is_normal_user && Entry.where(id, entry.id, customer_id: @user.customer_id, dept_id: user.departments.ids).exists?
end

private

def is_normal_user
  user.user_type == 'NORMAL_USER'.freeze
end

def is_admin
  user.user_type == 'ADMIN'.freeze
end

end

当然只是一个模板

【讨论】:

感谢您的快速回复。我会试试这个。我遇到的问题是,当我们创建条目记录时,该记录应该具有相应的部门 ID。对于普通用户,分配给他一个部门;这里没问题。对于管理员,将分配多个部门;因此,加载了多个部门能力记录。并且当管理员创建条目记录时,总是可以分配能力列表中的第一个部门 id 而不是我打算做的。 当您创建条目时,您需要从用户记录中传递 dept_id 和 customer。 你不应该使用 cancan 来创建记录。 如果您是管理员,只需在表单中将其 deps 列表显示为选项即可。 注意到您的回复。谢谢

以上是关于基于部门的 Rails CanCanCan 资源能力的主要内容,如果未能解决你的问题,请参考以下文章

Rails - CanCanCan - 常用能力

Rails 设计角色模型和 CanCanCan - 定义能力

Rails、Devise、Role Model 和 CanCanCan - 定义能力

rails+devise+cancancan+rolify注册登录多角色权限管理

大型有状态服务基于 K8s 的落地实践——按部门租户隔离

PostsController #index中的NameError