我正在尝试使用CanCan来限制我网站上的评论可见性。 在我的评论模型中定义了一个枚举:
enum access_right: {nobody: 0, somebody: 1, everyone: 2}
以下是我当前ability.rb文件的摘录:
class Ability
include CanCan::Ability
def initialize(user, session={})
user ||= User.new # guest user (not logged in)
# Comments
can [:create, :read, :update, :destroy], Comment, person_id: person.id
can [:read], Comment, access_right: [:everyone, Comment.access_rights[:everyone]]
...
end
end
起初我只是使用:
can [:read], Comment, access_right: 2
但即使这在获取记录时有效:
Comment.accessible_by(...)
在检查对象这样的对象的权限时不起作用:
can? :read, @a_comment
因为那时@ a_comment.access_right ==“everyone”(而不是2)
所以我在网上找到了这个:CanCanCommunity issue 102。 建议的解决方案对我不起作用,就像直接使用“每个人”一样:
can [:read], Comment, access_right: ["everyone", Comment.access_rights[:everyone]]
会给出不正确的结果。获取记录时,它背后的sql查询如下所示:
SELECT `comments`.* FROM `comments` WHERE `comments`.`access_right` IN (0,2))
在这种情况下,“everyone”似乎被转换为整数(0)。
然后我找到了一个变通方法,我当前的能力文件,感谢符号(:每个人)。 但是当使用can时,事情将不再起作用了? :read,@ a_comment(使用accessible_by时sql是正确的)
有谁知道如何纠正这个问题?
如何根据枚举来定义能力,这些能力既可以在获取记录时进行验证,也可以用can?
进行验证谢谢!
编辑:它可能与此CanCanCommunity issue 65有关,但我无法使其发挥作用。
答案 0 :(得分:0)
可以使用CanCan block syntax:
来实现# Please note this is an Array of Strings, not Symbols
allowed_access_rights = %w[everyone]
can :read, Comment, ["access_right IN (?)", Comment.access_rights.values_at(allowed_access_rights)] do |comment|
comment.access_right.in? allowed_access_rights
end
尽管在模型上定义范围并将其传递给此处而不是使用原始SQL条件很有吸引力,例如:
can :read, Comment, Comment.with_access_right(allowed_access_rights) do |comment| … end
实际上这是一个糟糕的主意,因为它的灵活性要差得多,请参阅CanCan docs。