Dois-je sauter l'autorisation, avec Cancan, d'une action qui instancie une ressource?
-
26-09-2019 - |
Question
J'écris une application Web pour choisir des listes aléatoires de cartes à partir de plus grands ensembles de cartes. J'ai un modèle de carte et un modèle de carton. Les deux modèles ont un ensemble complet de 7 actions (: index ,: nouveau ,: show, etc.). Le cartesetsController a une action supplémentaire pour créer des ensembles aléatoires: :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
J'ai ajouté le conçu pour l'authentification et le canne pour les autorisations. J'ai des utilisateurs avec un rôle «éditeur». Les éditeurs sont autorisés à créer de nouveaux cartes. Les utilisateurs invités (les utilisateurs qui ne se sont pas connectés) ne peuvent utiliser que :index
et :show
Actions. Ces autorisations fonctionnent comme conçue. Les éditeurs peuvent actuellement utiliser les deux :random
et le :new
actions sans aucun problème. Les utilisateurs invités, comme prévu, ne le peuvent pas.
# app/controllers/card_sets_controller.rb
class CardSetsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
load_and_authorize_resource
Je souhaite permettre aux utilisateurs invités d'utiliser le :random
action, mais pas le :new
action. En d'autres termes, ils peuvent voir de nouveaux ensembles aléatoires, mais pas les sauver. Le bouton "Enregistrer" sur le :random
La vue de l'action est masquée (telle que conçue) des utilisateurs invités. Le problème est la première chose la :random
Action fait est de créer une nouvelle instance du modèle Cardset pour remplir la vue. Quand Cancan essaie de load_and_authorize_resource
Un nouvel carton, il lance une exception Cancan :: AccessEnedied. Par conséquent, la vue ne se charge jamais et l'utilisateur invité est servi un message "Vous devez vous connecter ou vous inscrire avant de continuer".
# app/controllers/card_sets_controllers.rb
def random
@card_set = CardSet.new( :name => "New Set of 10", :set_type => "Set of 10" )
Je me rends compte que je peux dire load_and_authorize_resource
pour sauter le :random
Action en passant :except => :random
à l'appel, mais c'est juste "mauvais" pour certaines raisons.
Quel est le "droit" façon de faire ça? Dois-je créer le nouvel ensemble aléatoire sans instancier un nouveau carton? Dois-je aller de l'avant et ajouter l'exception?
Mise à jour
Je n'ai pas inclus ma classe de capacité ci-dessus. Je l'ai mis à jour pour inclure l'action «: aléatoire», mais cela ne fonctionne toujours pas tout à fait correct.
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
La solution
J'ai trouvé mon problème. Cancan n'était pas du tout le problème! La ligne suivante dans mon contrôleur de cartes a lancé l'exception et rediriger mes utilisateurs (non connectés) vers la page du journal:
before_filter :authenticate_user!, :except => [:show, :index]
Je l'ai changé pour lire:
before_filter :authenticate_user!, :except => [:show, :index, :random]
Et maintenant, le code fonctionne comme prévu: les utilisateurs invités peuvent afficher les nouveaux ensembles aléatoires créés, mais ne peuvent pas les «enregistrer» à moins qu'ils ne se connectent d'abord.
Ainsi, mon vrai problème était avec Devise (ou, en fait, ma configuration de divise) et non avec Cancan du tout.
Autres conseils
Eh bien, la bonne chose serait d'utiliser la classe Cancan Capacité pour définir les règles d'autorisation correctes.
en capacité.rb
def initialize(user)
#everyone
can [:read, :random], [CardSet]
#everyone who is editor
if user.editor?
can [:new, :create], [CardSet]
etc
Le problème est que la première chose: l'action aléatoire est de créer une nouvelle instance du modèle Cardset pour remplir la vue. Lorsque Cancan essaie de charger_and_authorize_resource un nouvel carton, il lance une exception Cancan :: AccessEnedied.
Bien que Cancan autorise l'action du contrôleur, la construction d'une nouvelle instance dans l'action aléatoire (c'est-à-dire CardSet.new) n'est pas dans la portée de Cancan. Vous obtenez probablement l'erreur car vous n'avez aucune règle définie dans Ability.rb pour une action aléatoire. Mon exemple ci-dessus devrait résoudre votre problème