リソースをインスタンス化するアクションの認可をカンカンでスキップする必要がありますか?
-
26-09-2019 - |
質問
私は、より大きな完全なカードのセットからカードのランダムリストを選択するためのWebアプリを作成しています。カードモデルとカードセットモデルがあります。両方のモデルには、7つのアクションの完全な安らかなセットがあります(:index、:new、:showなど)。 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は承認用に追加しました。 「編集者」の役割を持つユーザーがいます。編集者は新しいカードセットを作成できます。ゲストユーザー(ログインしていないユーザー)は、 :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
アクションは、ビューを記入するためにカードセットモデルの新しいインスタンスを構築することです。カンカンが試みるとき load_and_authorize_resource
新しいカードセットでは、Cancan :: Accessdenied Exceptionをスローします。したがって、ビューは決してロードされず、ゲストユーザーには「継続する前にサインインまたはサインアップする必要がある」メッセージが提供されます。
# 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
電話に、しかしそれはただ感じます "違う" 何らかの理由で。
何ですか "右" これを行う方法は?新しいカードセットをインスタンス化することなく、新しいランダムセットを作成する必要がありますか?先に進んで例外を追加する必要がありますか?
アップデート
上記の能力クラスは含まれていませんでした。 「:ランダム」アクションを含めるように更新しましたが、それでもまったく正しく機能していません。
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
解決
私は自分の問題を見つけました。カンカンはまったく問題ではありませんでした!カードセットコントローラーの次の行は、例外をスローし、ゲスト(ログインしていない)ユーザーをログインページにリダイレクトしていました。
before_filter :authenticate_user!, :except => [:show, :index]
読むように変更しました:
before_filter :authenticate_user!, :except => [:show, :index, :random]
そして、コードは意図したとおりに機能します。ゲストユーザーは、作成された新しいランダムセットを表示できますが、最初にログインしない限り「保存」することはできません。
したがって、私の本当の問題は、Devise(または実際には、Devise構成)であり、Cancanではなくでした。
他のヒント
まあ、正しいことは、CANCAN能力クラスを使用して正しい承認ルールを定義することです。
infily.rb
def initialize(user)
#everyone
can [:read, :random], [CardSet]
#everyone who is editor
if user.editor?
can [:new, :create], [CardSet]
等
問題は、最初にランダムアクションが行うことは、ビューを記入するためにカードセットモデルの新しいインスタンスを構築することです。 Cancanが新しいカードセットをload_and_anuthorize_resourceにしようとすると、cancan :: accessdenied例外がスローされます。
Cancanはコントローラーのアクションを承認しますが、ランダムアクション(IE Cardset.new)で新しいインスタンスを構築することはCancanの範囲内ではありません。ランダムアクションのためにability.RBで定義されているルールがないため、おそらくエラーが発生します。上記の私の例はあなたの問題を解決する必要があります