将CanCan与enum一起使用时的问题可以吗?和accessible_by()

时间:2014-10-23 22:59:38

标签: ruby-on-rails ruby enums cancan cancancan

我正在尝试使用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有关,但我无法使其发挥作用。

1 个答案:

答案 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