【发布时间】:2014-09-29 15:43:43
【问题描述】:
假设有这样的建模: 公司,有很多用户,有很多会议,通过会议有很多计划,通过计划有很多活动,通过活动有很多问题。
假设还有一个用户模型,有一个角色字段混合各种角色的二进制加法。 这些角色中很少有:
- 跨公司。
- 版主。
- 管理员(与此问题需要的版主几乎相同)。
然后,就有了这个 Participation 对象。参与属于用户以及会议,并定义了更多角色,这些角色可以是跨公司的任何角色。基本上,它允许用户成为一组会议的主持人,而不是全局的。用户上定义的任何角色都会取代参与中的角色。
现在,我正在努力为此类模型找到正确的 Cancancan 能力定义。困难的部分似乎是考虑参与角色的定义。
在能力声明的开头,我分解了权限以便于使用:
# Decompose rights.
cross = user.is? :cross_company
admin = user.is? :administrator
modo = user.is? :moderator
只分解了用户角色,还没有关于参与角色的任何内容。
这是我已经开始工作的一个例子。
# Any user can read it's own company. Any cross-company user can read any company.
can :read, Company, cross ? nil : { id: user.company_id }
# Only cross-company admins can create a new company.
can :create, Company if cross && admin
# Updating a company.
can :update, Company do |c|
# User is admin and...
admin &&
(
# User is cross or...
cross ||
# User belongs to this company.
user.company_id==c.id
)
end
cannot :destroy, Company
到目前为止一切顺利,我能够做更复杂的场景。例如,事件对象是这样授权的:
conditions = {}
# User can only see events he is participating into, unless he is admin.
conditions.deep_merge! id: user.event_ids unless admin
# User can only see events related to his company, unless he is cross-company.
conditions.deep_merge! planning: { conference: { company_id: user.company_id } } unless cross
can :read, Event, conditions
非常好。列出事件对象的 RESTful 控制器仅显示授权对象。
现在,让我们继续讨论 Question 对象(Question 属于事件,属于计划,属于会议,本身属于公司)。 基本上,任何用户都应该能够看到他提出的问题(Easy-peasy,question.user_id==user_id)。具有全局“主持人”标志的用户应该能够看到其他用户提出的任何问题。跨公司的版主应该能够看到任何问题。
但是,这种行为有一个例外。当用户(非管理员非 modo)有一个参与对象将他链接到一个事件,该事件在参与中具有一些压倒性的角色(例如,给定用户可能是单个会议的主持人),他应该能够看到来自的任何问题会议活动中的任何用户,他被授权为主持人。 我被困在这一点上:
# Only questionable events can have questions.
conditions = { event: { questionable: true } }
# Administrator / Moderator can see all questions, others can't.
conditions.deep_merge! user_id: user.id unless admin || modo
# The conference a question belongs to has to be owned by the same company as the user, unless he's cross company.
conditions.deep_merge! event: { planning: { conference: { company_id: user.company_id } } } unless cross
can :read, Question, conditions
我怎样才能覆盖行阅读
conditions.deep_merge! user_id: user.id unless admin || modo
所以不仅全局管理员/版主可以这样做,而且参与定义的单一角色的用户也可以这样做?目标当然是能够定义访问控制器时使用的 SQL,但我似乎无法找到解决这个问题的好方法。
有没有人用不同的方法解决了这种范式?
提示:问题控制器正在使用嵌套资源 (/api/events/1/questions.json)。如何从ability.rb 文件中获取正在使用的事件的 ID,以便我还可以检查当前用户参与此特定事件的情况?
谢谢! 皮埃尔。
【问题讨论】:
标签: ruby-on-rails cancan