Devo pular a autorização, com Cancan, de uma ação que instancia um recurso?

StackOverflow https://stackoverflow.com/questions/2831720

  •  26-09-2019
  •  | 
  •  

Pergunta

Estou escrevendo um aplicativo da web para escolher listas aleatórias de cartões de cartões maiores e completos. Eu tenho um modelo de cartão e um modelo de conjunto de cartões. Ambos os modelos têm um conjunto completo de 7 ações (: Índice, novo,: show etc.). O CardetsController tem uma ação extra para criar conjuntos aleatórios: :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

Adicionei o Deviso para autenticação e CanCan para autorizações. Tenho usuários com uma função de 'editor'. Os editores podem criar novos cartões. Usuários convidados (usuários que não fizeram login) podem usar apenas o :index e :show ações. Essas autorizações estão funcionando conforme projetado. Os editores podem atualmente usar os dois :random e a :new ações sem problemas. Usuários convidados, como esperado, não podem.

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

Eu quero permitir que usuários convidados usem o :random ação, mas não o :new ação. Em outras palavras, eles podem ver novos conjuntos aleatórios, mas não salvá -los. O botão "salvar" no :random A visão da ação está oculta (como projetado) dos usuários convidados. O problema é que a primeira coisa que a :random A ação faz é criar uma nova instância do modelo de conjunto de cartões para preencher a visualização. Quando Cancan tenta load_and_authorize_resource Um novo conjunto de cartões, ele lança uma exceção de cancan :: accessdenied. Portanto, a visualização nunca é carregada e o usuário convidado é servido por uma mensagem "Você precisa fazer login ou se inscrever antes de continuar".

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

Eu percebo que posso dizer load_and_authorize_resource para pular o :random ação passando :except => :random para a ligação, mas isso apenas parece "errado" por algum motivo.

Qual é o "certo" maneira de fazer isso? Devo criar o novo conjunto aleatório sem instantar um novo conjunto de cartões? Devo ir em frente e adicionar a exceção?

Atualizar

Não incluí minha aula de habilidade acima. Eu o atualizei para incluir a ação ': aleatória', mas ainda não está funcionando bem.

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
Foi útil?

Solução

Eu encontrei meu problema. Cancan não era o problema! A linha a seguir no meu controlador de conjunto de cartões foi lançar a exceção e redirecionar os usuários do meu convidado (não conectado) para a página de login:

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

Eu mudei para ler:

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

E agora o código funciona como pretendido: os usuários dos hóspedes podem visualizar os novos conjuntos aleatórios criados, mas não podem 'salvá -los', a menos que faça login primeiro.

Portanto, meu verdadeiro problema estava com o Devise (ou, na verdade, minha configuração de invenção) e não com o CANCAN.

Outras dicas

Bem, a coisa certa seria usar a classe CANCAN CAPACIDADE para definir as regras de autorização corretas.

em habilidade.rb

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

etc.

O problema é que a primeira coisa: a ação aleatória é criar uma nova instância do modelo de conjunto de cartões para preencher a visualização. Quando o Cancan tenta load_and_authorize_resource um novo conjunto de cartões, ele lança uma exceção de cancan :: accessdenied.

Enquanto a CANCAN autoriza a ação do controlador, a criação de uma nova instância em ação aleatória (ou seja, o CardSet.New) não está no escopo de Cancan. Você provavelmente recebe o erro porque não tem regras definidas no habilidade.rb para ação aleatória. Meu exemplo acima deve resolver seu problema

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top