Я пишу веб-приложение для выбора случайных списков карт из больших, полных наборов карт. У меня есть модель 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