使用块来定义CanCan中的异能会引发异常

Ton*_*ony 3 ruby-on-rails cancan

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

def index
    @req_host_w_port = request.host_with_port
    @products = Product.accessible_by(current_ability, :index)
end
Run Code Online (Sandbox Code Playgroud)

当我尝试使用该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)
Run Code Online (Sandbox Code Playgroud)

我的能力课看起来像这样:

can :index, Product do |product|
   product && !!product.approved_at
end
Run Code Online (Sandbox Code Playgroud)

这看起来像一个非常简单的例子,所以我很惊讶它失败了,想知道我是否忽略了一些简单的事情(即我盯着我的代码太长时间).

我做了更多的探测并进行了一个简单的测试.如果你看下面的代码,一个例子工作正常,一个失败,他们应该实际做同样的事情.

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

# This fails
can :index, Product do |product|
    product && product.approved_at.nil?
end
Run Code Online (Sandbox Code Playgroud)

所以问题似乎在于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
Run Code Online (Sandbox Code Playgroud)

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

can :manage, [Account], :account_manager_id => user.id
Run Code Online (Sandbox Code Playgroud)

任何关于这个问题的见解都会很棒!我还在CanCan github页面上提出了一个问题,但我已经到了可能需要放弃库的地步.但是,据我所知,许多人成功使用CanCan,这是基本功能,我认为我必须做错事.特别是因为git repo在3天前更新了,Ryan Bates在README中提到了Rails 3的支持.

谢谢!

Ton*_*ony 6

好的,所以我浏览了wiki,看到accessible_by在定义块时不起作用.看起来有点奇怪有这个限制并且在README中没有提到它,但至少我知道它是库的限制而不是我的或者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
Run Code Online (Sandbox Code Playgroud)