获取表示用户CanCan能力的字符串

Tom*_*man 9 caching authorization cache-invalidation cancan

我想缓存一个Post视图,但视图取决于当前用户的权限(例如,我只显示"编辑"链接current_user.can?(:edit, @post))

所以我希望我的缓存键包含当前用户的CanCan功能的表示,这样当用户的能力改变时我可以使缓存无效

那么:我怎样才能得到一个表示当前用户能力的字符串,以便2个具有相同能力的不同用户生成相同的"能力字符串"?

我已经尝试过user.ability.inspect,但是对于具有相同能力的不同用户,这不会产生相同的字符串

RGB*_*RGB 9

编辑:CanCanCan修订版

从CanCanCan 1.12版(CanCan的社区延续版)开始,Ability.new(user).permissions返回包含给定用户所有权限的哈希.

上一个答案(CanCan):

这可能有点复杂......但在这里......

如果将指定的User传递给CanCan所需的Ability模型,则可以使用instance_variable_get访问该用户角色的定义,然后将其分解为您想要的任何字符串值.

>> u=User.new(:role=>"admin")
>> a=Ability.new(u)
>> a.instance_variable_get("@rules").collect{ 
      |rule| rule.instance_variable_get("@actions").to_s
   }
=> ["read", "manage", "update"]
Run Code Online (Sandbox Code Playgroud)

如果您想知道这些规则所针对的模型,您可以访问@subjects实例变量来获取其名称.

这是我与之合作的能力的模型布局(pp)

Ability:0x5b41dba @rules=[
  #<CanCan::Rule:0xc114739 
    @actions=[:read], 
    @base_behavior=true, 
    @conditions={}, 
    @match_all=false, 
    @block=nil, 
    @subjects=[
      User(role: string)]>, 
  #<CanCan::Rule:0x7ec40b92 
    @actions=[:manage], 
    @base_behavior=true, 
    @conditions={}, 
    @match_all=false, 
    @block=nil, 
    @subjects=[
      Encounter(id: integer)]>, 
  #<CanCan::Rule:0x55bf110c 
    @actions=[:update], 
    @base_behavior=true, 
    @conditions={:id=>4}, 
    @match_all=false, 
    @block=nil, 
    @subjects=[
      User(role: string)]>
]
Run Code Online (Sandbox Code Playgroud)


Ron*_*nze 7

我想把我的能力发送到JS,并且关注这篇文章,这里是我的帮助方法,你可以用来将你的用户能力转换为你控制器中的数组.然后我在数组上调用.to_json并将其传递给javascript.

def ability_to_array(a)
  a.instance_variable_get("@rules").collect{ |rule| 
  { 
    :subject => rule.instance_variable_get("@subjects").map { |s| s.name }, 
    :actions => rule.instance_variable_get("@actions").map { |a| a.to_s }
  }
}
end
Run Code Online (Sandbox Code Playgroud)

这是我实现can()方法的Backbone.js模型:

var Abilities = Backbone.Model.extend({
  can : function(action, subject)
  {
    return _.some(this.get("abilities"), function(a) {
      if(_.contains(a["actions"], "manage") && _.contains(a["subject"], "all")) return true;
      return _.contains(a["actions"], action) && _.contains(a["subject"], subject);
    });
   }
});
Run Code Online (Sandbox Code Playgroud)