1

所以我有以下设置:

class User < AR
  has_many :memberships
  has_many :user_groups, through: :memberships
  has_many :organizations, through: :memberships
end

class Membership < AR
  belongs_to :user
  belongs_to :user_group
  belongs_to :organization
end

class UserGroup < AR
  has_many :memberships
  has_many :users, through: :memberships
  has_many user_groups, through: :memberships
end

因此,一个用户可以是不同组织中多个用户组的成员,即他/她可以是组织 A 的产品经理和组织 B 的文章经理和评论经理。

所以为了能够问can? :manage, an_article_instance我需要有这样的能力设置:

class Ability
  if user.is_content_manager_for(currently_selected_organization)
    can :manage, Article

  elsif user.is_admin_for(currently_selected_organization)
    can :manage, User, memberships: { organization_id: currently_selected_organization }
  end
end

后端的 Web 界面应该有一个选择菜单,用户可以在其中选择他/她想要在哪个组织工作。所以我在考虑可能将当前选择的组织存储在会话中,因为它是整个工作会话中的持久数据。

currently_selected_organization但是在能力(或任何其他)模型中访问像(或直接会话)这样的辅助方法实际上会违反 MVC 模式。我在几个地方读到这不好,等等等等。

所以我想知道是否有更好/更清洁的方法来做到这一点?

4

1 回答 1

4

好的,所以我用不同的方法解决了这个问题。CanCan 添加了一个current_ability方法,ActionController::Base该方法实例化一个新Ability对象并将该current_user对象传递给它。可以简单地在自己的控制器中覆盖该current_ability方法,所以我最终这样做了:

class ApplicationController < ActionController::Base
  def current_ability
    @current_ability ||= Ability.new(current_user, Organization.find_by(id: cookies[:current_organization])
  end
end

class Ability
  include CanCan::Ability

  def initialize(user, currently_selected_organization)
    if user.is_admin_for(currently_selected_organization
      # ...
    end
  end
end

这样它就不会破坏 MVC 模式,我最终也没有包含帮助模块或破解任何东西。

于 2013-08-07T18:09:52.490 回答