Caching 获取表示用户的字符串';坎坎的能力

Caching 获取表示用户的字符串';坎坎的能力,caching,authorization,cancan,cache-invalidation,Caching,Authorization,Cancan,Cache Invalidation,我想缓存Post视图,但该视图取决于当前用户的权限(例如,如果当前用户可以,我只显示“编辑”链接)(:edit,@Post)) 因此,我希望我的缓存密钥包含当前用户CanCan能力的表示,以便在用户能力发生变化时使缓存失效 那么:如何获得一个表示当前用户能力的字符串,以便具有相同能力的两个不同用户生成相同的“能力字符串” 我尝试了user.ability.inspect,但是对于具有相同能力的不同用户,这不会产生相同的字符串 从CanCanCan的1.12版(CanCan的社区延续版)开始,Ab

我想缓存
Post
视图,但该视图取决于当前用户的权限(例如,如果
当前用户可以,我只显示“编辑”链接)(:edit,@Post)

因此,我希望我的缓存密钥包含当前用户CanCan能力的表示,以便在用户能力发生变化时使缓存失效

那么:如何获得一个表示当前用户能力的字符串,以便具有相同能力的两个不同用户生成相同的“能力字符串”


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


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

先前的答案(坎坎):

这可能有点复杂…但事情是这样的

如果将指定的用户传递到CanCan所需的能力模型中,则可以使用实例\变量\ 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"]
如果您想知道这些规则适用于哪些模型,可以访问@subjects实例变量以获取其名称

这是我使用的能力的模型布局(pp)

能力:0x5b41dba@rules=[
#, 
#, 
#4}, 
@match_all=false,
@块=零,
@科目=[
用户(角色:字符串)]>
]

我想将我的能力发送到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
下面是我的Backbone.js模型,它实现了can()方法:


我想总结一下,您必须使用您选择的内容构建数组,保存它,然后将其内容转换为字符串,再次使用to_s:)这是一个依赖于实现细节的黑客攻击。唯一依赖的是用户正在使用CanCan gem,而OP正在使用它。当使用CanCanIts实例变量时,该功能和用户类本质上是可用的,但没有文档记录,并且可能会在更新版本中更改。它还掩盖了潜在的重要细节(如输出中最后一条规则的条件)。这就是为什么您应该坚持使用公共API或找到其他方法!从CanCanCan(CanCan的社区延续版)的1.12版开始,
Ability.new(user.permissions
返回给定用户所有权限的哈希值。您也可以只使用:subject=>rule.instance_variable_get(@subjects”).map{s|s.to_s},就好像您使用s.name并且您的主题包含符号一样,它将出错
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
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);
    });
   }
});