Ответ 1
Возобновленный ответ:
Для обработки ролей для вашей модели хорошие варианты - использовать gem rolify. С его помощью вы можете легко определить столько ролей, сколько хотите, и связать столько роли, сколько хотите для своего Пользователя. Он прост в использовании, просто следуйте официальной документации здесь.
CanCan (или его sucessor CanCanCan) используется для обработки разрешений. Вы определите, какой пользователь должен выполнять каждую роль (определенную с помощью ролика) в файле app/models/ability.rb
. Затем в контроллерах или представлениях вы просто проверяете, разрешено ли пользователю выполнять действие для ресурса. Например, в вашем контроллере вы подтверждаете авторизацию, например @comment = Comment.new(params); authorize! :create, @comment
, и в своем представлении вы подтверждаете авторизацию как if can? :create, Comment
. Refuer к официальной документации здесь, чтобы узнать, как настроить и использовать CanCan.
Полагая это на вашу конкретную проблему:
Добавьте в свой Gemfile файл Rolify (gem "rolify"
) и CanCan (gem "cancan"
).
Выполните команду оболочки rails rails g rolify Role User
, чтобы создать новый класс с именем Role (или используйте имя, которое вы предпочитаете), и добавьте некоторые методы класса в ваш существующий класс User. Поскольку новая роль класса добавит роль таблицы в вашу базу данных, вам нужно запустить rake db:migrate
(при использовании ActiveRecord).
Добавьте resourcify
в любой класс, к которому будет обращаться Пользователь. Например:
class Forum < ActiveRecord::Base
resourcify
end
После того, как вы выполнили эти шаги, ваш пользовательский класс будет оснащен методами add_role
, remove_role
и has_role
, и вы можете использовать их для добавления столько ролей, сколько пожелаете:
user.add_role :superadmin
user.add_role :fundraiser
user.has_role? :superadmin
# >> true
user.has_role? :fundraiser
# >> true
И вы можете даже разделить роль на один ресурс или экземпляр:
user.add_role :cyclist, Forum
user.add_role :coordinator, Forum.first
user.has_role? :cyclist, Forum
# >> true
user.has_role? :cyclist, Store
# >> false
user.has_role? :coordinator, Forum.first
# >> true
user.has_role? :coordinator, Forum.second
# >> false
Итак, вы можете написать свой класс User следующим образом:
class User < ActiveModel::Base
rolify
has_many :jobs
# checking
def is_superadmin?
self.has_role?('superadmin')
end
# changing
def add_new_role(role)
self.update_attributes(accepted_at: Time.now) if self.is_only_potential?
self.add_role(role)
end
def make_superadmin!
add_new_role('superadmin')
end
def denounce_superadmin!
remove_role('superadmin')
end
end
Для аутентификации этих ролей вы можете использовать CanCan. Выполните команду оболочки rails rails g cancan:ability
, чтобы сгенерировать файл app/models/ability.rb
, где вы будете определять разрешения для своих ролей.
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new # guest user
if user.has_role? :superadmin
can :manage, All # can manage (Read, Create, Update, Destroy, ...) everything
elsif user.has_role? :forum_admin
can :manage, Forum # can manage (Read, Create, Update, Destroy, ...) any Forum
elsif user.has_role? :store_admin
can :manage, Store do |store| # Can manage only its own store
store.try(:user) == user
end
elsif user.has_role? :forum_member
can :create, Post do |post|
if post.forum.members.include? user
true
end
end
can :destroy, Post do |post|
post.try(:user) == user
end
can :update, Post do |post|
post.try(:user) == user
end
elsif ...
else # Users without role
can :read, All
end
end
end
В ваших контроллерах вы можете вызвать метод authorize!
. Например:
# app/controllers/posts_controller.rb
def create
@post = Post.new(params[:post])
@post.user = current_user
authorize! :create, @post
if @post.save
redirect_to @post
else
render :action => 'new'
end
end
Или вы можете включить faloowing в начале вашего контроллера, и ресурс автоматически загружается и авторизируется (или нет) перед каждым действием:
class PostController < ApplicationController
load_and_authorize_resource :post
...
def create
authorize! :create, @post
if @post.save
redirect_to @post
else
render :action => 'new'
end
end
Посмотрите этот учебник на RailsCast для начала работы с CanCan.
Надеюсь, это поможет вам решить вашу проблему.