3

我正在使用 Ryan Bate 的 CanCan gem 来定义能力,但一些基本功能失败了。我有一个产品模型和产品控制器,其中我的索引操作如下所示:

def index
    @req_host_w_port = request.host_with_port
    @products = Product.accessible_by(current_ability, :index)
end

当我尝试使用该accessible_by方法检索产品时出现错误,我收到此错误:

Cannot determine SQL conditions or joins from block for :index Product(id: integer, secret: string, context_date: datetime, expiration_date: datetime, blurb: text, created_at: datetime, updated_at: datetime, owner_id: integer, product_type_id: integer, approved_at: datetime)

我的能力课是这样的:

can :index, Product do |product|
   product && !!product.approved_at
end

这似乎是一个非常简单的例子,所以我很惊讶它失败了,并想知道我是否忽略了一些简单的事情(即盯着我的代码太久)。

我做了更多的探索并运行了一个简单的测试。如果您查看下面的代码,一个示例工作正常,一个示例失败,它们实际上应该做同样的事情。

# This works
can :index, Product, :approved_at => nil

# This fails
can :index, Product do |product|
    product && product.approved_at.nil?
end

所以问题似乎在于 CanCan 处理这些块的方式。我更深入地研究了这个库,发现了错误出现的地方——在 CanCan 的能力类定义中:

def relevant_can_definitions_for_query(action, subject)
      relevant_can_definitions(action, subject).each do |can_definition|
        if can_definition.only_block?
          raise Error, "Cannot determine SQL conditions or joins from block for #{action.inspect} #{subject.inspect}"
        end
      end
    end

所以我检查了这个only_block?方法是什么。如果 can 定义有一个块但没有条件,则该方法返回 true,这对我来说没有意义,因为块的全部意义在于在块内定义条件对于以下语法来说太复杂时:

can :manage, [Account], :account_manager_id => user.id

关于这个问题的任何见解都会很棒!我还在 CanCan github 页面上提交了一个问题,但我已经到了可能需要放弃该库的地步。但是,我知道很多人都成功地使用了 CanCan,这是我认为我一定做错了什么的基本功能。特别是因为 git 存储库在 3 天前更新,并且 Ryan Bates 在 README 中提到了 Rails 3 支持。

谢谢!

4

3 回答 3

6

好的,所以我浏览了 wiki,发现accessible_by在定义块时不起作用。有这个限制并且没有在自述文件中提到它似乎有点奇怪,但至少我知道这是库的限制,而不是我的或 Ryan Bates 的代码中的错误。对于那些感兴趣的人,上面定义我的能力的正确方法如下:

# will fail    
can :index, Product do |product|
   product && product.approved_at.nil?
end

# will pass
can :index, Product
cannot :index, Product, :approved_at => nil
于 2010-08-24T14:22:23.193 回答
3

我也遇到过这个问题,有时您只能通过块(Ruby 代码)表达能力/权限,而不能将其表达为 SQL 条件或命名范围。

作为一种解决方法,我只是像通常在没有CanCan 的情况下那样做我的发现,然后我过滤该设置select!以仅包含用户实际有权查看的记录子集:

# Don't use accessible_by
@blog_posts = BlogPost.where(...)
@blog_posts.select! {|blog_post| can?(:read, blog_post)}

或更笼统地说:

@objects = Object.all
@objects.select! {|_| can?(:read, _)}
于 2011-09-08T22:17:18.343 回答
0

我提交了一张票以将其添加到文档中:

https://github.com/ryanb/cancan/issues/issue/276

于 2011-02-11T17:05:06.560 回答