Durante o desenvolvimento de um aplicativo da web, me deparei com um problema com os usuários tendo uma função por empresa.
Por exemplo, você tem um usuário que pode gerenciar duas empresas. Ele criou a primeira empresa e, portanto, é o proprietário e administrador dessa empresa, mas foi convidado para uma segunda empresa, onde tem acesso limitado de conteúdo, então é o moderador dessa empresa.
No nível dos dados, tenho uma tabela User criada pelo Devise, uma tabela Companies e um Role que o Rolify criou para mim.
Porque eu quero saber qual usuário tem qual função em uma empresa; Preciso de uma tabela para armazenar seus IDs, então criei uma tabela de unidades.
create_table :unities do |t|
t.integer :role_id
t.integer :user_id
t.integer :company_id
t.timestamps
end
Depois disso, criei um modelo chamado Unity, que usarei para facilitar a manipulação de funções.
unit.rb
class Unity < ActiveRecord::Base
attr_accessible :role_id, :user_id, :company_id
belongs_to :role
belongs_to :company
belongs_to :user
end
e também adicionei associações a modelos de empresa, função e usuário.
user.rb
class User < ActiveRecord::Base
rolify
cattr_accessor :current_role
has_many :unities
has_many :roles, through: :unities
has_many :companies, through: :unities
end
Eu adicionei current_role para que eu possa verificar qual função o usuário possui em uma empresa em que ele está, mas eu irei falar sobre isso mais tarde
role.rb
class Role < ActiveRecord::Base
has_many :unities
has_many :users, through: :unities
has_many :companies, through: :unities
end
company.rb
class Company < ActiveRecord::Base
cattr_accessor :current
has_many :unities
has_many :users, through: :unities
has_many :roles, through: :unities
end
Aqui adicionei uma empresa atual, para poder verificar em qual empresa está ativa irei utilizá-la mais tarde.
O que é cattr_accestor?
http://www.cowboycoded.com/2010/04/20/ruby-cattr_accessor-vs-attr_accessor/
Depois de definir associações entre essas três tabelas, podemos agora definir funções e habilidades em Ability.rb que é usado por CanCan
Mas antes disso, precisamos encontrar uma função de usuário atual.
Como um usuário pode gerenciar várias empresas, mas em níveis diferentes, primeiro precisamos encontrar em qual empresa ele está atualmente, e podemos obter isso nos parâmetros.
Portanto, em um ApplicationController, adicione dois métodos.
class ApplicationController < ActionController::Base
before_filter :initialize_company, :initialize_user_role
def initialize_company
if params.has_key?(:company_id)
Company.current = Company.find(params[:company_id])
end
end
def initialize_user_role
unless Company.current.nil?
User.current_role = Unity.where(company_id: Company.current.id, user_id: current_user.id).first.role.name
end
end
end
E agora estamos prontos para criarability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if User.current_role == 'admin'
can :manage, :all
else
if User.current_role == 'moderator'
can :read, Products
can :update, Products
cannot :destroy, Products
cannot :create, Products
cannot :manage, Client
end
can :read, :all
end
end
end
Em ApplicationController, podemos obter current_role e compará-lo com a função que desejamos.
if User.current_role == 'admin'
Neste artigo, expliquei como as coisas devem funcionar e o princípio básico da criação de uma função por empresa e usuário. No próximo artigo, descreverei como alterar as permissões do usuário e como adicionar funções aos usuários.
E aqui está a essência para uma melhor visualização
https://gist.github.com/vmarcetic/6049929
Esta é apenas minha maneira de fazer as coisas. Se você tem alguma sugestão, ou sabe como fazer melhor, escreva um comentário.