使用 CanCan 嵌套子元素

Nested Child Elements with CanCan

Ruby 新手,正在处理内部应用程序的更改。

我正在使用 CanCan,以便我们可以限制对页面的访问。

我有以下有效的代码,但我知道有更好的方法可以为未知数量的子元素编写代码。

一个用户有一个直线经理,谁有一个直线经理...e.t.c。我正在尝试实现树状层次结构,以便高层管理人员可以查看他们的员工帐户,但前提是他们是该员工层次结构的一部分。在下面的示例中,John 应该可以查看 Jane 和 Jack 的个人资料,但不能查看 Josh 或 James 的个人资料。

  +-------------+----------------------+--------+
  | user_id     | name                 | parent |
  +-------------+----------------------+--------+
  |           1 | JOHN SMITH           |   NULL |
  |           2 | JANE SMITH           |      1 |
  |           3 | JACK SMITH           |      2 |
  |           4 | JOSH SMITH           |      5 |
  |           5 | JAMES SMITH          |   NULL |
  +-------------+----------------------+--------+

Ability.rb的一部分

class Ability
    include CanCan::Ability
    def initialize(user)
      user ||= User.new
      can :read, User, id: user.id
      can :read, User, line_manager: user
      can :read, User, line_manager: {line_manager: user}
      can :read, User, line_manager: {line_manager: {line_manager: user}}
      can :read, User, line_manager: {line_manager: {line_manager: {line_manager: user}}}
      can :read, User, line_manager: {line_manager: {line_manager: {line_manager: {line_manager: user}}}}
      can :read, User, line_manager: {line_manager: {line_manager: {line_manager: {line_manager: {line_manager: user}}}}}

感谢任何帮助,因为这不是一个长期的解决方案,因为嵌套的数量可能会增加,并且需要对不仅仅是用户进行处理。

一个高效的解决方案是从数组中的数据库中收集所有 ID,并授予用户访问它们的权限。没有 DB-Queries 的更脏的解决方案是这样的:

can :read, User.all do |r_user|
  until r_user.line_manager.nil? do |manager|
    return true if manager == user
    r_user = manager
  end
  return false
end

(注意代码未经测试,但像这样的东西应该可以工作)。 但这会一次又一次地循环所有用户。我建议通过查询收集 ID

您可以使用 closure_tree gem,这将允许您管理模型中的层次结构。然后,您可以像这样在模型中添加一个实例方法:

def managed_by? user_id
  self_and_ancestors_ids.include? user_id
end

然后你可以像这样将障碍传递给你的康康舞能力

can :read, User, User.all do |fetched_user|
  fetched_user.managed_by? user.id
end