Sollte ich die Autorisierung mit Cancan über eine Maßnahme überspringen, die eine Ressource instanziiert?
-
26-09-2019 - |
Frage
Ich schreibe eine Web -App, um zufällige Kartenlisten aus größeren, vollständigen Kartensätzen auszuwählen. Ich habe ein Kartenmodell und ein Kartenset -Modell. Beide Modelle haben einen vollständigen Satz von 7 Aktionen (: Index,: neu,: show usw.). Der CardsetsController hat eine zusätzliche Aktion zum Erstellen von zufälligen Sätzen: :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
Ich habe Devise für Authentifizierung und Cancan für Autorisierungen hinzugefügt. Ich habe Benutzer mit einer "Editor" -Rolle. Die Redakteure dürfen neue Kartensätze erstellen. Gastbenutzer (Benutzer, die sich nicht angemeldet haben) können nur die verwenden :index
und :show
Aktionen. Diese Genehmigungen arbeiten wie entworfen. Redakteure können derzeit beide verwenden :random
und die :new
Handlungen ohne Probleme. Wie erwartet können Gastbenutzer nicht.
# app/controllers/card_sets_controller.rb
class CardSetsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
load_and_authorize_resource
Ich möchte den Gastnutzern erlauben, die zu verwenden :random
Aktion, aber nicht die :new
Aktion. Mit anderen Worten, sie können neue zufällige Sets sehen, sie aber nicht retten. Die Schaltfläche "Speichern" auf der :random
Die Ansicht von Action ist vor den Gastnutzern versteckt (wie entworfen). Das Problem ist, das erste, was das ist :random
Aktion erstellt eine neue Instanz des Kartenset -Modells, um die Ansicht auszufüllen. Wenn Cancan versucht zu load_and_authorize_resource
Ein neues Kartenset, das eine Ausnahme von Cancan :: AccessDenied ausgelöst hat. Daher wird der Ansicht nie geladen und dem Gastbenutzer wird eine Nachricht "Sie müssen sich anmelden oder anmelden" bedient.
# app/controllers/card_sets_controllers.rb
def random
@card_set = CardSet.new( :name => "New Set of 10", :set_type => "Set of 10" )
Mir ist klar, dass ich es sagen kann load_and_authorize_resource
um das zu überspringen :random
Aktion durch Passieren :except => :random
zum Anruf, aber das fühlt sich einfach an "falsch" aus irgendeinem Grund.
Was ist das "Rechts" Weg, dies zu tun? Sollte ich den neuen zufälligen Satz erstellen, ohne einen neuen Kartenset zu instanziieren? Soll ich die Ausnahme hinzufügen?
Aktualisieren
Ich habe meinen Fähigkeitsklassen oben nicht hinzugefügt. Ich habe es aktualisiert, um die Aktion von ': Random' einzuschließen, aber es funktioniert immer noch nicht ganz richtig.
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
Lösung
Ich fand mein Problem. Cancan war überhaupt nicht das Problem! Die folgende Zeile in meinem Cardset -Controller war die Ausnahme und habe meinen Gast (nicht angemeldete) Benutzer zur Anmeldung auf Seite umleiten:
before_filter :authenticate_user!, :except => [:show, :index]
Ich habe es geändert, um zu lesen:
before_filter :authenticate_user!, :except => [:show, :index, :random]
Und jetzt funktioniert der Code wie beabsichtigt: Gastbenutzer können die neuen zufälligen Sets anzeigen, können sie jedoch nicht "speichern", es sei denn, sie melden sich zuerst an.
Mein eigentliches Problem war also mit Devise (oder eigentlich meine Devise -Konfiguration) und überhaupt nicht mit Cancan.
Andere Tipps
Das Richtige wäre, die Cancan -Fähigkeitsklasse zu verwenden, um die richtigen Autorisierungsregeln zu definieren.
in Fähigkeit.RB
def initialize(user)
#everyone
can [:read, :random], [CardSet]
#everyone who is editor
if user.editor?
can [:new, :create], [CardSet]
etc
Das Problem ist, dass die: zufällige Aktion als erstes eine neue Instanz des Kartenset -Modells erstellt, um die Ansicht auszufüllen. Wenn Cancan versucht, einen neuen Kartenset zu laden_and_authorize_resource, wird eine Ausnahme von Cancan :: AccessDenied ausgelöst.
Während Cancan die Controller -Aktion autorisiert, befindet sich eine neue Instanz in zufälliger Aktion (dh CardSet.NEW) nicht im Rahmen von Cancan. Sie erhalten wahrscheinlich den Fehler, da Sie in der Fähigkeit. RB für zufällige Aktionen keine Regeln definiert haben. Mein obiger Beispiel sollte Ihr Problem lösen