Должен ли я пропустить авторизацию с CanCan для действия, которое создает экземпляр ресурса? - PullRequest
0 голосов
/ 14 мая 2010

Я пишу веб-приложение для выбора случайных списков карт из больших, полных наборов карт. У меня есть модель Card и модель CardSet. Обе модели имеют полный набор RESTful из 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 для авторизации. У меня есть пользователи с ролью редактора. Редакторы могут создавать новые CardSets. Гостевые пользователи (пользователи, которые не вошли в систему) могут использовать только действия :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, чтобы заполнить представление. Когда cancan пытается load_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

Ответы [ 2 ]

3 голосов
/ 14 мая 2010

Я нашел свою проблему. CanCan не был проблемой вообще! Следующая строка в моем контроллере CardSet выдавала исключение и перенаправляла моих гостевых (не авторизованных) пользователей на страницу входа:

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

Я изменил его на:

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

И теперь код работает так, как задумано: гостевые пользователи могут просматривать созданные новые случайные наборы, но не могут «сохранить» их, пока они не войдут в систему.

Итак, моя настоящая проблема была с Devise (или, собственно, с моей конфигурацией Devise), а не с CanCan вообще.

0 голосов
/ 14 мая 2010

Что ж, правильно было бы использовать класс способностей CanCan для определения правильных правил авторизации.

в Ability.rb

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

и т.д.

Проблема в том, что первое, что делает: случайное действие, это создает новый экземпляр модели CardSet, чтобы заполнить представление. Когда cancan пытается загрузить_and_authorize_resource новый CardSet, он генерирует исключение CanCan :: AccessDenied.

Хотя CanCan разрешает действие контроллера, создание нового экземпляра в произвольном действии (то есть CardSet.new) не входит в сферу применения CanCan. Вы, вероятно, получите ошибку, потому что у вас нет правил, определенных в Ability.rb для случайных действий. Мой пример выше должен решить вашу проблему

...