Criando Uma App Com Devise CanCan e Bootstrap
Recentemente surgiu essa dúvida no GuruPI. Para tentar ajudar aqueles que estão começando, bem como meu colega que estava com a dúvida, resolvi criar esse post e colocar a app criada no Github.
Sobre as gems usadas no post
Uma gem bastante fexível para autenticação em aplicações web, bem como genrenciamento dos dados do usuário.
Gem que irá nos permitir fazer o gerenciamento de permissões para cada usuário do sistema.
Esta gem nos ajudará a reconfigurar toda a estrutura de layout padrão do Rails, nos dando uma visualização mais agradável da aplicação atraves do bootstrap.
Seguindo com o nosso post, essa será mais ou menos a estrutura de nossa aplicação:
1 2 3 4 5 6 7 8 9 |
|
Vamos criar nossa aplicação com o seguinte comando:
rails new exemplo_cancan_e_devise
Depois de criar vamos deletar o seguinte arquivo public/index.html
rm public/index.html
Agora colocaremos as gems que iremos usar no arquivo Gemfile:
1 2 3 4 |
|
Com isso nossa app sabe que queremos usar essas gems, então vamos executar o seguinte comando, para podermos usar os geradores de cada gem:
bundle install
Eu iriei fazer um breve comentário sobre cada comando usado de cada gem aqui, para se aprofundar mais você deve ir ate a url colocada no inicio do post de cada gem.
Esse comando irar criar um arquivo com o nome devise.rb, dentro de config/initializers com as configurações padrões do devise e colocará devise_for :users, dentro do arquivo config/routes, assim teremos todas as rotas do devise.
rails generate devise:install
Esse irá criar um model com as definições do devise, bem como uma migration com os campos padrões do devise
rails generate devise user
Comando que executa todas as migrations(nada mais é que uma forma organizada de criar tabelas, deletar, alterar ou criar novos campos no banco de dados).
rake db:migrate
Irá gerar a views usadas pelo devise dentro de app/views/devise
rails generate devise:views
Como esse comando vamos criar um controller dentro da pasta app/controllers, assim poderemos acessar alguns dados do usuário nas views que o devise nao cria.
rails g controller users
Aqui o cancan cria uma classe dentro da pasta models com o nome ability, essa classe irá manter, gerenciar as permissões em cada usuário
rails g cancan:ability
Com o comando scaffold eu posso criar um CRUD rapidamente, passando o nome e logo em seguida os campos com seus tipos.
Aqui ele cria um controller um model uma migration com o campo name do tipo string
rails g scaffold roles name:string
O paramentro role:references irar criar um campo role_id do tipo inteiro dentro da tabela e adiciona belongs_to role, dentro do model Permission
rails g scaffold permissions action:string subject_class:string role:references
rake db:migrate
Com isso vamos colocar os arquivos js, bem como suas chamadas dentro do arquivo application.js encontrado em app/assets/javascritps e de css em app/assets/stylesheets do boostrap.
rails g bootstrap:install
Aqui estou criando um arquivo com nome application com o css do boostrap dentro de views/layouts
rails g bootstrap:layout application fixed
Esses comando da gem bootstrap ira varer as tabelas e inserir dentro das views de cada pasta passada, dentro de app/views, substituindo as tags em html e css, colocando as do boostrap em cada campo da tabela.
rails g bootstrap:themed Users
rails g bootstrap:themed Roles
rails g bootstrap:themed Permissions
Agora vamos criar 2 migrations uma para adicionar role_id dentro da tabela users e a outra para fazer o gerenciamento de muitos para muitos entre Permission e Role.
rails g migration add_role_id_to_users
rails g migration create_table_permissions_roles
Abra os arquivos que se encontram em db/migrate e modifique-os:
1 2 3 |
|
1 2 3 4 5 |
|
Execute novamente:
rake db:migrate
Depois de tudo isso feito nossa aplicação esta quase pronta, faltando apenas algumas validações e modificações no layout e a configuração do arquivo ability.
Começaremos pelas validações e relacionamentos, como existia a necessidade de termos a permissão para cada view no banco, apareceu o relacionamento muitos para muitos entre Permission e Role, logo vamos deixa-los assim:
1 2 3 4 5 6 |
|
1 2 3 4 5 6 7 |
|
Aproveitando vamos colocar também no model User.
1 2 3 4 5 6 7 8 9 10 11 |
|
Explicando:
Com o has_and_belongs_to_many, estou dizendo que existe um relacionameto muitos para muitos.
has_many :users, :dependent => :restrict, aqui estou dizendo que Role pode ter muitos usuários, mas que se existir algum usuário com um role, esse role nao pode ser deletado(:dependent => :restrict).
belongs_to aqui entende-se que dentro dessa tabela que o usa nos temos um campo id de outra tabela.
validates_uniqueness_of :action, :scope => :subject_class, aqui eu estou dizendo que o campo action deve ser unico e passando :scope eu faço uma verificação de exclusividade com o campo subject_class, assim eu nao vou poder ter 2x action index para subject_class User. Isso simplesmente irá evitar de termos 2x a mesma permissão dentro de Role.
validates_presence_of aqui ele verifica se o campo foi preenchido.
Assim como o cancan, o :dependent => :restrict gera uma exception, fazendo com que a aplicação não tenha um comportamento adequado, para ajustarmos isso, adicionamos os seguintes códigos dentro de app/controllers/application_controller.rb
1 2 3 4 5 6 7 |
|
Agora vamos até o arquivo app/models/ability.rb e modifica-lo:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
O que basicamente ele faz é verifica se o role do usuario logado é admin, se for o usuário tera todas as permissões na aplicação, agora senão for admin, ele irá verificar as permissões do usuário para cada action em cada model.
Agora vamos fazer as modificações na view devise/registration/edit.html.erb e new.html.erb, para podermos modificar e adicionar o role do usuário, adicione o seguinte trecho:
1 2 3 4 5 6 |
|
Hum têm alguns helpers que devem ser criados, vamos ao arquivo app/helpers/application_helper.rb e coloque isso:
1 2 3 4 5 6 7 |
|
O primeiro me retorna todos os Models da aplicação e o segundo todos os roles.
Seguindo a leitura da dúvida do meu colega, tem-se uma imagem, como eu não queria criar uma tabela para fazer os gerenciamentos dos models da app, pensei em usar somente um metodo para fazer isso é aqui que entra o helper get_model_names_sub lol.
Abrimos o arquivo _form.html.erb da pasta views/roles e modificamos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Ficou um pouco feio, mas o post ja estava muito grande, então vamos seguindo.
Eu criei um arquivo seed, então é so dar uma olhada aqui, para os que não sabem esse arquivo serve para popular o banco de dados e fica dentro da pasta db. O comando é o seguinte:
rake db:seed
Ah falta modificar o menu, abra o arquivo app/layouts/application.html.erb:
1 2 3 4 5 6 7 8 9 10 11 |
|
Assim o menu só será exibido se o usuário tiver permissão, também ficou faltando adicionar load_and_authorize_resource dentro dos controllers, sem ele o cancan não vai poder fazer as verificações de permissão.
E finalizando o nosso controller de users:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Teve tambem essa pequena adição no arquivo app/views/layouts/application.html.erb:
1 2 3 |
|
Essa dentro do arquivo app/assets/javascript/boostrap_and_overrides.css.less:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
E essa dentro do config/application.rb:
1 2 3 4 5 6 7 8 9 |
|
Essa é parra mudar as mensagens de validação, as outras são mudanças no comportamento do css.
Simples e fácil lol, o código esta aqui, espero não ter esquecido de nada.