0

私は、より大きな完全なカード セットからカードのランダム リストを選択する Web アプリを作成しています。Card モデルと CardSet モデルがあります。どちらのモデルにも、7 つのアクション (:index、:new、:show など) の完全な RESTful セットがあります。CardSetsController には、ランダム セットを作成するための追加のアクションがあります: :random.

# app/models/card_set.rb
class CardSet < ActiveRecord::Base
  belongs_to :creator, :class_name => "User"
  has_many :memberships
  has_many :cards, :through => :memberships

# app/models/card.rb
class Card < ActiveRecord::Base
  belongs_to :creator, :class_name => "User"
  has_many :memberships
  has_many :card_sets, :through => :memberships

認証用の Devise と承認用の CanCan を追加しました。「編集者」の役割を持つユーザーがいます。編集者は、新しい CardSet を作成できます。ゲスト ユーザー (ログインしていないユーザー) は、 アクション:index:showアクションのみを使用できます。これらの承認は設計どおりに機能しています。編集者は現在、:random:newアクションの両方を問題なく使用できます。予想どおり、ゲスト ユーザーはできません。

# app/controllers/card_sets_controller.rb
class CardSetsController < ApplicationController
  before_filter :authenticate_user!, :except => [:show, :index]
  load_and_authorize_resource

ゲスト ユーザーがアクションを使用できるようにしたいのですが、アクションは使用:randomできません:new。つまり、新しいランダム セットを表示できますが、保存することはできません。アクション ビューの[保存] ボタンは、:random(設計どおり) ゲスト ユーザーには表示されません。問題は、:randomアクションが最初に行うことは、CardSet モデルの新しいインスタンスを作成してビューを埋めることです。cancanload_and_authorize_resourceが新しい CardSet を試行すると、CanCan::AccessDenied 例外がスローされます。したがって、ビューは読み込まれず、ゲスト ユーザーには「続行する前にサインインまたはサインアップする必要があります」というメッセージが表示されます。

# app/controllers/card_sets_controllers.rb
def random
  @card_set = CardSet.new( :name => "New Set of 10", :set_type => "Set of 10" )

呼び出しに渡すことでアクションload_and_authorize_resourceをスキップするように指示できることに気づきましたが、それは何らかの理由で「間違っている」と感じています。:random:except => :random

これを行う「正しい」方法は何ですか?新しい CardSet をインスタンス化せずに、新しいランダム セットを作成する必要がありますか? 先に進んで例外を追加する必要がありますか?

アップデート

上記の能力クラスは含めませんでした。「:random」アクションを含めるように更新しましたが、まだ正しく機能していません。

class Ability
  include CanCan::Ability

  def initialize( user )
    user ||= User.new # User hasn't logged in

    if user.admin?
      can :manage, :all if user.admin?
    else
      # All users, including guests:
      can :read, [Card, CardSet]
      can :random, CardSet

      # All users, except guests:
      can :create, [Card, CardSet] unless user.role.nil?
      can :update, [Card, CardSet] do |c|         
        c.try( :creator ) == user || user.editor?
      end

      if user.editor?
        can [:create, :update], [Card, CardSet]
      end
    end
  end
end
4

2 に答える 2

3

問題が見つかりました。CanCan はまったく問題ではありませんでした。CardSet コントローラの次の行は、例外をスローし、ゲスト (ログインしていない) ユーザーをログイン ページにリダイレクトしていました。

before_filter :authenticate_user!, :except => [:show, :index]

私はそれを読むように変更しました:

before_filter :authenticate_user!, :except => [:show, :index, :random]

これで、コードは意図したとおりに機能します。ゲスト ユーザーは、作成された新しいランダム セットを表示できますが、最初にログインしない限り、それらを「保存」することはできません。

したがって、私の本当の問題は Devise (または、実際には私の Devise 構成) にあり、CanCan にはまったくありませんでした。

于 2010-05-14T15:06:35.323 に答える
0

そうですね、CanCan アビリティ クラスを使用して正しい承認規則を定義するのが正しいでしょう。

Ability.rbで

  def initialize(user)
#everyone
    can [:read, :random], [CardSet]
#everyone who is editor
    if user.editor?
      can [:new, :create], [CardSet]

問題は、:random アクションが最初に行うことは、ビューを埋めるために CardSet モデルの新しいインスタンスを作成することです。cancan が新しい CardSet を load_and_authorize_resource しようとすると、CanCan::AccessDenied 例外がスローされます。

CanCan はコントローラー アクションを承認しますが、ランダム アクション (つまり、CardSet.new) で新しいインスタンスを構築することは、CanCan の範囲内ではありません。ランダム アクションのルールが Ability.rb に定義されていないため、おそらくエラーが発生します。上記の私の例はあなたの問題を解決するはずです

于 2010-05-14T09:32:43.720 に答える