3

Ryan Bate の CanCan gem を使用して能力を定義していますが、いくつかの基本機能が失敗しています。Product モデルと Products コントローラーがあり、インデックス アクションは次のようになります。

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

これは非常に単純な例のように見えるので、これが失敗していることに驚いており、何か単純なことを見落としているのではないかと思います (つまり、コードを長時間見つめているなど)。

もう少し調べて、簡単なテストを実行しました。以下のコードを見ると、1 つの例は正常に動作し、1 つの例は実際にはまったく同じことを行うべきところで失敗しています。

# 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 をうまく使用していることを理解しています。これは非常に基本的な機能であり、何か間違ったことをしているに違いないと思います。特に、3 日前に git リポジトリが更新され、Ryan Bates が README で Rails 3 のサポートについて言及しているためです。

ありがとう!

4

3 に答える 3

6

さて、私はwikiを調べて、accessible_byブロックを定義するときにそれが機能しないことを確認しました。この制限があり、READMEに記載されていないのは少し奇妙に思えますが、少なくともライブラリの制限であり、私のコードやRyanBatesのコードのバグではないことはわかっています。興味のある人のために、上記の私の能力を定義する適切な方法は次のとおりです。

# 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 に答える