2010
06.01

Escrever um script que roda em daemon (backgounrd) e repete algum comando de tempos em tempos é extremamente simples e pode resolver vários problemas.

Há um tempo atrás precisei de um listening em um diretório que ficasse mudando permissões de arquivos que eram importados automáticamente. O script ficou assim:

#! /bin/bash
#Script para dar permissão de acesso aos arquivos para o faturamento
#Roda em daemon

#loop infinito
while((1)); do
  #faz o que tem que ser feito
  chown -R nobody:faturamento /home/faturamento/importacoes;
  #pausa por 5 segundos (ou quantos você quiser)
  sleep 5;
# o "&" no final é quem faz o script rodar em daemon
done &

#por fim, mostra uma mensagem
echo 'Script rodando em daemon...'

Se você tiver outras formas de fazer isso (acredito que deva existir outras até melhores), mande através dos comentários :)

2010
05.23

Introdução

Este post é um resumo de comandos úteis para administração de banco de dados PostgreSQL.

Instalação

Versão 8.3 no Ubuntu 9.10

sudo aptitude install postgresql-8.3 postgresql-client-8.3 pgadmin3 pgadmin3-data postgresql-server-dev-8.3 libpostgresql-ocaml-dev

Versão 8.4 no Ubuntu 10.04

sudo aptitude install postgresql postgresql-contrib libpq-dev pgadmin3

Criando uma senha

sudo su postgres -c psql postgres
ALTER USER postgres WITH PASSWORD 'sua_senha';

Gerenciar bancos de dados

Criar uma base

create database dbname with owner=postgres encoding='utf8';

Renomear uma base

alter database "old_name" rename to "new_name";

Apagar uma base

drop database dbname;

Backup (dump) e restore

Dump de uma base

pg_dump dbname -h localhost -U postgres > backup.sql

Dump de uma tabela apenas

pg_dump dbname -h localhost -U postgres > backup.sql --table=nome_tabela;

Dump de uma base apenas com algumas tabelas

pg_dump dbname -h localhost -U postgres > backup.sql --table=nome_tabela --table=outra_tabela;

Dump de uma base sem determinada tabela

pg_dump dbname -h localhost -U postgres > backup.sql --exclude-table=nome_tabela;

Dump de uma base excluindo várias tabelas

pg_dump dbname -h localhost -U postgres > backup.sql --exclude-table=nome_tabela --exclude-table=outra_tabela;

Restore de uma base

psql dbname -h localhost -U postgres < backup.sql

Dump dos usuários de uma base

pg_dumpall -g -U postgres -h localhost > users.sql

Comandos especiais em queries

Data

select (current_date + integer '7') as nome_campo;

Veja mais exemplos aqui.

Erros comuns

Duplicate key value violates unique constraint
Ao migrar uma base para PostgreSQL ou fazer alguma coisa errada sem querer, o seguinte erro pode aparecer:
PGError: ERROR: duplicate key value violates unique constraint “tablename_pkey”

Para resolver:

select setval('entities_id_seq', (select max(id) from entities)+1);

Personalizando o psql

alterando o pager

\pset pager off
\pset pager off
\pset pager always
\pset pager occasionally
\pset pager at random

Exebir ‘(null)’ quando um campo for null

\pset null '(null)'

Veja mais configurações aqui.

2010
05.18

No final do ano passado criei um projetinho no github pra organizar o passo-a-passo da instalação das ferramentas que uso (como Rails e PostgreSQL) e também de alguns dotfiles. Esse post é apenas uma cópia da atual versão do README do projeto.

O link do projeto é http://github.com/lucascaton/lcaton-setuplinux.

Recentemente atualizei meu Ubuntu para a versão 10.04 e esse script de instalação está atualizado para ser usado nesta versão. Esses passos incluem a instalação do Ruby através do RVM, Rails 2.3.5, PostgreSQL 8.4 e algumas outras coisas. Sempre que eu atualizar o Ubuntu ou mudar algum procedimento ou ainda um dotfile, vou alterar no projeto do github também.


Versão atual: Ubuntu 10.04 (desktop edition – 32 bits)

Instalação básica

Antes de mais nada

sudo aptitude update

Open SSH Server

sudo aptitude install openssh-server

Git & gitg

sudo aptitude install git-core gitg

Curl

sudo aptitude install curl

Suporte à arquivos compactados

sudo aptitude install rar p7zip-full

GTK Record My Desktop e Mencoder / Mplayer

sudo aptitude install gtk-recordmydesktop mplayer mencoder ffmpeg

nmap (Usage ‘sudo nmap -sS ’ pra saber as portas abertas de uma máquina remota)

sudo aptitude install nmap

Criar DVDs e converter vídeos

sudo aptitude install devede

Gimp (a partir da versão 10.04 do Ubuntu o Gimp não vem instalado por padrão)

sudo aptitude install gimp

Fonts true type

sudo aptitude install msttcorefonts

Wine

sudo aptitude install wine

Copiar arquivos deste projeto

git clone git://github.com/lucascaton/lcaton-setuplinux.git ~/.setuplinux

Instalar fonte Monaco

sudo mkdir /usr/share/fonts/truetype/myfonts
cd /usr/share/fonts/truetype/myfonts
sudo cp ~/.setuplinux/files/Monaco_Linux.ttf .
sudo chown root:root Monaco_Linux.ttf
sudo mkfontdir
cd ..
fc-cache

Gvim

sudo aptitude install vim-gnome ncurses-term exuberant-ctags

Vimfiles

mv ~/.vim ~/vim_old
git clone git://github.com/lucascaton/cmarques-vimfiles.git ~/.vim
mv ~/.vimrc ~/vimrc_old
mv ~/.vim/vimrc ~/.vimrc

Gmate

git clone git://github.com/lexrupy/gmate.git
cd gmate && sh install.sh && cd .. && rm -rf gmate

DotFiles

cp ~/.setuplinux/dotfiles/.bashrc ~
cp ~/.setuplinux/dotfiles/.fonts.conf ~
cp ~/.setuplinux/dotfiles/.gemrs ~
cp ~/.setuplinux/dotfiles/.gitconfig ~
cp ~/.setuplinux/dotfiles/.irbrc ~

PostgreSQL

sudo aptitude install postgresql postgresql-contrib libpq-dev pgadmin3

Configurar a senha do PostgreSQL

sudo passwd postgres
su - postgres
psql -c "ALTER USER postgres WITH PASSWORD 'sua_senha'" -d template1

Sqlite3

sudo aptitude install sqlite3

JDK

sudo aptitude install openjdk-6-jre-headless

Ruby on Rails

Bibliotecas necessárias

Readline headers

sudo aptitude install libreadline5-dev

C++ compiler (necessário para o Ruby)

sudo aptitude install build-essential

OpenSSL development headers (necessário para o Ruby)

sudo aptitude install libssl-dev

Sqlite support

sudo aptitude install libsqlite3-dev sqlite-dev libdbd-sqlite3-ruby libsqlite3-ruby libsqlite3-ruby1.8

Mysql Client (necessário para a gem ‘mysql’)

sudo aptitude install libmysqlclient15-dev

libxslt (necessário para a gem ‘capybara’)

sudo aptitude install libxslt-dev

Sphinx (necessário para a gem ‘thinking-sphinx’)

wget http://www.sphinxsearch.com/downloads/sphinx-0.9.9.tar.gz
tar -xzvf sphinx-0.9.9.tar.gz && cd sphinx-0.9.9
./configure --with-pgsql && sudo make && sudo make install
cd .. && rm -rf sphinx-0.9.9

Image Magick (necessário para a gem ‘gruff’)

sudo aptitude install imagemagick libmagick9-dev

Cups Sys (necessário para a gem ‘cups’)

sudo apt-get install libcupsys2-dev

Avahi – dnssd (necessário para a gem ‘specjour’)

sudo apt-get install libavahi-compat-libdnssd-dev

RVM

bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head )

Atualizar RVM

rvm update --head

Rubies

rvm install ree
rvm install ruby-1.9.1
rvm install jruby

Gemset

gem sources -a http://gems.github.com
rvm gemset create caton
cp ~/.setuplinux/files/caton.gems .
rvm gemset import caton.gems
rm caton.gems
rvm --default ree@caton

Outros

Outros softwares:

  • Google Chrome
  • TweetDeck
  • Eclipse (IDE)
  • Skype
2010
02.01

Bom, este é um post curto (mas que acredito que terá outros similares) com pequenas soluções interessantes usando linha de comandos – uma quase “bala de prata” pra quem usa Linux e Mac.

Como deletar vários sub-diretórios de uma só vez

Eu precisei fazer isso quando queria retirar os sub-diretórios do svn de uma pasta, ou seja, “desversionar” um projeto.

Só pra entender melhor, um projeto versionado pelo svn, segue o padrão da seguinte estrutura de diretórios:

./.svn
./app/.svn
./app/models/.svn
./config/.svn

O comando pra remover todos estes diretórios é:

find -name ".svn" -type d -exec rm -rvf {} \;

E significa: procure por tudo que tiver o nome .svn e que for um diretório e quando encontrar, execute um comando rm -rvf nele. Os paramêtros do rm significam: r – recursive (pra apagar diretórios), v – verbose (exibir as pastas que estão sendo apagadas), f – force (não pedir confirmação pra apagar).

Como extrair uma parte de um arquivo grande pra outro menor

Eu precisei fazer isso porque o arquivo do qual seria extraído uma parte era grande demais (1,5gb) e o vim e o gedit (ou qualquer outro) teriam dificuldade pra abri-lo.

Vamos supor então que eu tenha um arquivo chamado banco.dump com 20 milhões de linhas e eu queria extraír o conteúdo das linhas 12.000.000 até a linha 12.000.500 para um outro arquivo que vou chamar de novo.txt.

O comando pra fazer isso é:

cat -n banco.dump | head -n 12000500 | tail -n 500 > novo.txt

Explicando: o paramêtro passado no head é a linha final (12000500) do range desejado. E o 500 passado no tail é quantas linhas pra trás ele deve pegar. E pra finalizar é só jogar tudo pra dentro do novo.txt.

2009
12.18

Há mais de um ano atrás, postei no meu antigo blog sobre o Google Chrome, quando até então era novidade. Dias depois, como ainda não havia nenhuma versão pra Linux, o abandonei e voltei para o bom e velho Panda-vermelho (pois é, o Firefox não é uma raposa!). Demorou – bastante a propósito, mas o Google finalmente liberou uma versão estável pro pinguim e pro Mac.

O primeiro browser que usei foi o Netscape, entre 1998 ~ 2000, até mudar para Internet Explorer, o qual deixei quando conheci a versão 1.0 do Firefox, o qual revolucionou o mundo dos browsers. Em paralelo com o Firefox, acompanhei três versões diferentes do Opera, o qual também gosto bastante e atualmente é meu browser secundário. E agora estou (re)experimentando o Chrome. Será que é hora de mudar novamente?

Novidades interessantes

Há 5 dias estou testando o Google Chrome beta (v. 4.0.249.30) para Linux (utilizo Ubuntu 9.04 durante o dia e Ubuntu 9.10 à noite, mas não notei diferença em relação à isso) e as boas notícias são:

  • Progresso de upload – Quando você faz o upload de uma imagem ou qualquer arquivo para um site, é informado no rodapé o progresso de upload (em %). Isso realmente fazia muita falta;
  • Pin tab – alguns sites você sempre mantém aberto (aka Gmail) então porque não fixá-los no browser? É pra isso que serve as “pin tabs”, abas que ficam no cantinho, discretas e sempre ali disponíveis.
  • Abas no lugar do título da janela – Economia de espaço colocando as abas na barra de título. Isso deixa o layout ainda mais clean;
  • Textareas redimensionáveis – Qualquer textarea pode ser redimensionado, basta clicar no canto inferior direito dele e arrastar. Pode ser útil às vezes;
  • Nunca reinicie o browser – Instalação e desistalação de extensions (aka add-ons) não requerem reinicialização do browser. Aplicação de temas (que a propósito funcionam muito bem) também não.
  • Um processo por aba – O que faz com que se algum site travar, o resto continua funcionando normalmente. Antes que atirem pedras em mim: ok, o Internet Explorer já fazia isso, mas não deixa de ser um diferencial em relação aos outros. É possível também “destacar” uma aba facilmente, transformando-a em uma janela separada. A partir da versão 3.5 do Firefox isso também é possível;
  • Economia de memória – Em pequenos testes que fiz, o Chrome usou cerca de 15% menos memória que o Firefox (v. 3.5.5);

Problemas

Em 5 dias de uso (média de 10 horas / dia), Google Chrome se mostrou bastante estável e não travou nenhuma vez sequer. Um problema que se repetiu duas vezes foi não carregar o Gmail de maneira correta e foi necessário limpar o cache pra fazê-lo voltar ao normal. Fora isso, nenhum outro inconveniente do tipo.

O maior problema de todos é, de longe, a falta de extensions. Perde feito se comparado com o Firefox nesse item. Mas acredito que logo isso já não será um problema: já estão surgindo várias extensions, cada vez mais rapidamente.

Ah, vale citar que no Mac alguns recursos ainda não estão disponíveis, como extensions e pin tabs, segundo um amigo que está testando a mesma versão do browser pra Mac.

Extensions

Testei 4 extensions:

    GMail Checker (v. 1.3) – mostra emails não lidos na inbox. Funcionou perfeitamente bem;
    Firebug Lite (v. 1.25) – achei o máximo quando encontrei. Só que simplesmente não funciona (e não fiquei perdendo muito tempo tentando fazê-lo funcionar);
    Gtalk (by marcelozlot) – Carregou minha lista de amigos, cheguei a ficar online, mas todo mundo ficava off. Tentei três vezes e desisti.
    Google Quick Scroll (v. 0.5.4) – excelente extension. Quando você busca algo no Google e entra em determinada página, ele te mostra onde os termos da busca foram encontrados nas páginas. Realmente fantástico.

Conclusão

Embora ainda esteja na versão beta, já está perfeitament estável. Vou continuar usando como browser padrão, mas ainda não é hora de desistalar o Firefox. Apaguei o Opera da minha máquina e agora o Firefox é o browser secundário. Recomendo que todos testem por alguns dias, como eu fiz e não tirem conclusões precipitadas, afinal… é um browser que promete!

2009
11.03

O problema

Um dos problemas enfrentados por desenvolvedores web quando não se tem um designer na equipe, é fazer o layout da aplicação, já que quase sempre é um de seus pontos fracos (pelo menos da maioria que eu conheço). Particularmente falando, embora aprecie muito a área, não é meu forte trabalhar com XHTML, CSS e resolver problemas de incompatibilidade de browsers.

As soluções

Bom, neste ponto, surgem várias soluções, mas não é interesante matar um mosquito com uma granada, então você deve estudar o que melhor lhe atende em cada projeto. Flex pode ser ótimo, mas sem dúvidas ele não é ideal pra todos os projetos. ExtJS é bacana, mas devemos ter atenção com a sua licença. Flash, JavaFX e SilverLight podem ter lá sua utilidade também, mas o que os programadores geralmente buscam é uma interface simples, com boa usabilidade e de fácil manutenção.

A solução que eu trago neste post é uma gem chamada web app theme. Através dela, torna-se extremamente fácil gerar layouts sem nenhuma dor de cabeça.

Como uma simples demonstração, segue alguns screenshots dos layouts gerados automaticamente:

Passo-a-passo

Primeiramente, instale a gem:

sudo gem install web-app-theme -s http://gemcutter.org

Ou instale como um plugin do rails:

script/plugin install git://github.com/pilu/web-app-theme.git

Vamos criar uma aplicação rails simples:

rails cool_albums
cd cool_albums
script/generate scaffold Album name:string artist:string date:date
rake db:migrate

Adicione ao seu config/routes.rb:

map.root :controller => :albums

Rode o seguinte comando pra gerar o tema:

script/generate theme application --app_name="My Cool Albums" --theme="drastic-dark"

O primeiro argumento (“application”) é o nome do layout que o generator vai criar (application.html.erb).
A opção –app_name especifica o nome usado no título das páginas e o parametro –theme define qual dos temas você quer usar. Verifique aqui os temas disponíveis.

Remova o arquivo public/index.html e o layout criado pela scaffold:

rm app/views/layouts/albums.html.erb
rm public/index.html

Agora inicie o server:

script/server

web-app-theme-example

Ok, ficou bom. Mas é possível aplicar um tema à todas as views geradas através do scaffold:

script/generate themed albums album --layout=application --with_will_paginate

Os dois primeiros parametros significam: controller e model, respectivamente. Controller “albums” e model “album”. A opção –layout é usada pelo generator themed para adicionar o menu. E se você quiser usar a gem will paginate, basta usar a opção –with_will_paginate e alterar a action index do controller, de:

@albums = Album.all

Para:

@albums = Album.paginate(:per_page => 10, :page => params[:page])

Para exibir mensagens de erro dentro dos forms gerados automaticamente, adicione as seguintes linhas ao seu config/environment.rb:

ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
  if html_tag =~ /<label/
    %|<div class="fieldWithErrors">#{html_tag} <span class="error">#{[instance.error_message].join(', ')}</span></div>|
  else
    html_tag
  end
end

Divirta-se… programando; já que você não perde mais tempo com layout :)

(Este tutorial foi baseado neste post de Andrea Franz)

2009
09.06

Introdução

Autorização é diferente de autenticação e segundo Oleg Dashevskii (criador do Acl9):

Ambas palavras iniciam com “aut”, mas tem significados diferentes! Autenticação é basicamente um mapeamento de credenciais (login e senha) ou OpenID para especificar a conta do usuário no sistema. E autorização é uma permissão de um usuário autenticado para executar alguma ação específica em algum lugar do sistema.

Hoje vou escrever dois tutoriais em um mesmo post, mas eles podem ser usados separadamente. O primeiro é sobre como usar o Authlogic pra fazer autenticação e o segundo é sobre como usar o Acl9 para gerenciar autorizações.

 

Pré-requisitos

Utilizei Ruby v1.8.6 com as seguintes gems: Rails v2.3.3, Authlogic v2.1.1, Acl9 v0.10.0 e Nifty-generators 0.3.0.

Instalação das gems

[sudo] gem sources -a http://gems.github.com
[sudo] gem install authlogic
[sudo] gem install be9-acl9
[sudo] gem install nifty-generators

 

Autenticação com AuthLogic

Esta parte do tutorial é praticamente a forma escrita do episódio #160 do RailsCasts.
Atenção: Nós iremos usar o nifty-generators pra facilitar, mas isso não é mandatório para poder utilizar authlogic ou acl9.

Preprarando um simples conteúdo estático

Crie um novo projeto rails:

rails authlogic_acl9

Antes de mais nada, gere um nifty_layout:

script/generate nifty_layout

Inclua no arquivo config/environment.rb a seguinte linha:

config.gem "authlogic"

Agora crie um controller para algumas páginas estáticas:

script/generate controller static_content index

Na página index.html.erb criada, eu escrevi:

<h1>Página inicial</h1>

Pra que esta seja a página inicial da app, apague o arquivo public/index.html e adicione a seguinte linha no config/routes.rb:

map.root :controller => "static_content", :action => "index"

User

Agora que já foi criado uma página estática simples, crie um scaffold para o User:

script/generate nifty_scaffold user username:string email:string password:string new edit

Para quem não conhece o nifty_scaffold, os últimos parametros que foram passados são os controllers (neste caso ‘new’ e ‘edit’ – com os quais ganhamos automáticamente o ‘create’ e ‘update’, por motivos óbvios).

Altere o migration da tabela Users para:

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :username
      t.string :email
      t.string :crypted_password
      t.string :password_salt
      t.string :persistence_token
      t.timestamps
    end
  end

  def self.down
    drop_table :users
  end
end

Exitem outras colunas interessantes que podem ser usadas, como por exemplo login_count (integer) e current_login_ip (string). Veja mais colunas neste link.

Gere a tabela:

rake db:migrate

Inclua a seguinte linha no seu models/user.rb:

class User < ActiveRecord::Base
  acts_as_authentic
end

Altere o users/_form.html.erb, incluindo um campo de confirmação de senha:

<% form_for @user do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :username %><br />
    <%= f.text_field :username %>
  </p>
  <p>
    <%= f.label :email %><br />
    <%= f.text_field :email %>
  </p>
  <p>
    <%= f.label :password %><br />
    <%= f.password_field :password %>
  </p>
  <p>
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation %>
  </p>
  <p><%= f.submit "Enviar" %></p>
<% end %>

O interessante é que o AuthLogic já reconhece esse campo e não cadastra o usuário se as senhas não coencidirem, exibindo um erro de validação.

Agora altere o users_controller.rb:

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])
    if @user.save
      flash[:notice] = "Usuário cadastrado com sucesso."
      redirect_to root_url
    else
      render :action => 'new'
    end
  end

  def edit
    @user = current_user
  end

  def update
    @user = current_user
    if @user.update_attributes(params[:user])
      flash[:notice] = "Dados do usuário alterados com sucesso."
      redirect_to root_url
    else
      render :action => 'edit'
    end
  end
end

Session

Vamos agora começar a gerenciar as sessões:

script/generate session user_session
script/generate nifty_scaffold user_session --skip-model username:string password:string new destroy

Na primeira linha, você vê um script (o qual faz parte do AuthLogic) que gera a session.
E na segunda, usamos novamente o nifty_scaffold, só que agora ignorando o model (com o parametro –skip-model), uma vez que ele já foi gerado pelo primeiro script (generate session).

Altere o user_sessions_controller.rb:

class UserSessionsController < ApplicationController
  def new
    @user_session = UserSession.new
  end

  def create
    @user_session = UserSession.new(params[:user_session])
    if @user_session.save
      flash[:notice] = "Usuário logado com sucesso."
      redirect_to root_url
    else
      render :action => 'new'
    end
  end

  def destroy
    @user_session = UserSession.find
    @user_session.destroy
    flash[:notice] = "Sessão finalizada com sucesso."
    redirect_to root_url
  end
end

E user_sessions/new.html.erb será a página de login:

<% title "Login" %>

<% form_for @user_session do |f| %>
  <%= f.error_messages %>
  <p>
    <%= f.label :username %><br />
    <%= f.text_field :username %>
  </p>
  <p>
    <%= f.label :password %><br />
    <%= f.password_field :password %>
  </p>
  <p><%= f.submit "Enviar" %></p>
<% end %>

Adicione no routes.rb as rotas para login e logout:

map.login "login", :controller => "user_sessions", :action => "new"
map.logout "logout", :controller => "user_sessions", :action => "destroy"

No layouts application.html.erb, inclua um menu que irá gerenciar o usuário e as sessões:

<div id="user_nav">
  <% if current_user %>
    <%= link_to "Editar", edit_user_path(:current) %> |
    <%= link_to "Logout", logout_path %> |
    <span>Bem vindo <strong><%= current_user.username %></strong>!</span>
  <% else %>
    <%= link_to "Registrar", new_user_path %> |
    <%= link_to "Login", login_path %>
  <% end %>
</div>

Pra finalizar, inclua dois métodos ao application_controller.rb, os quais retornam o usuário autenticado:

class ApplicationController < ActionController::Base
  helper :all # include all helpers, all the time
  protect_from_forgery # See ActionController::RequestForgeryProtection for details

  #Authlogic
  filter_parameter_logging :password

  helper_method :current_user

  private

  def current_user_session
  return @current_user_session if defined?(@current_user_session)
  @current_user_session = UserSession.find
  end

  def current_user
  return @current_user if defined?(@current_user)
  @current_user = current_user_session && current_user_session.record
  end
end

Pronto! O AuthLogic já está gerenciando suas sessões :)

Uma opção bem interessante é traduzir as mensagens, campos e modelos do Authlogic para pt-BR. O Patrick Espake explica como fazer isso, neste post.

 

Autorização com Acl9

Nesta segunda parte do tutorial, vamos gerenciar as autorizações atravéz do Acl9.
Bem, como eu disse no início do post, são dois tutoriais independentes, mas irei usar a aplicação que criamos no primeiro tutorial pra adiantar as coisas.

Inclua mais uma linha no seu config/environment.rb:

config.gem "be9-acl9", :source => "http://gems.github.com", :lib => "acl9"

Irei usar algumas actions sem sentido, apenas para efeito didático. Vamos então recriar o controller static_content:

script/generate controller static_content index index2 index3 index4 denied

Adicione as novas actions no routes.rb:

map.root :controller => "static_content", :action => "index"
map.resources :static_content, :collection => {:index2 => :get, :index3 => :get, :index4 => :get, :denied => :get}

No final do layout application.html.erb, inserimos um rodapé com alguns links, pra testar se as permissões de fato funcionam corretamente:

<div id="footer">
  <%= link_to 'index', :controller => 'static_content', :action => 'index' %> |
  <%= link_to 'index2', :controller => 'static_content', :action => 'index2' %> |
  <%= link_to 'index3', :controller => 'static_content', :action => 'index3' %> |
  <%= link_to 'index4', :controller => 'static_content', :action => 'index4' %>
</div>

Vamos trabalhar o rescue ‘AccessDenied’ no application_controller.rb:

rescue_from 'Acl9::AccessDenied', :with => :access_denied

def access_denied
  if current_user
    render :template => 'static_content/denied'
  else
    flash[:notice] = 'Acesso negado. Você precisa estar logado.'
    redirect_to login_path
  end
end

Este método faz o seguinte: se existir uma sessão de usuário e ocorrer esta excessão, significa que este usuário específico não tem permissão pra acessar tal recurso, então é renderizado o ‘static_content/denied’. Caso ele não esteja logado, aparece uma mensagem flash dizendo que ele precisa se logar e redireciona-o para tela de login.

Continuando, nós precisaremos de um model Role:

script/generate model Role name:string authorizable_type:string authorizable_id:integer

Altere a migration Roles para:

class CreateRoles < ActiveRecord::Migration
  def self.up
    create_table "roles", :force => true do |t|
        t.string   "name",              :limit => 40
        t.string   "authorizable_type", :limit => 40
        t.integer  "authorizable_id"
        t.timestamps
      end
  end

  def self.down
    drop_table :roles
  end
end

E o models/role.rb para:

class Role < ActiveRecord::Base
  acts_as_authorization_role
end

Assim, o Acl9 entende que está é a classe das regras de autorização.

Embora não seja necessário alterar nada na tabela Users, é necessário uma tabela intermediária dele com as regras, então crie a migration roles_users:

script/generate migration roles_users

E edite esta nova migration:

class RolesUsers < ActiveRecord::Migration
  def self.up
    create_table "roles_users", :id => false, :force => true do |t|
      t.integer  "user_id"
      t.integer  "role_id"
      t.datetime "created_at"
      t.datetime "updated_at"
    end
  end

  def self.down
  end
end

Não esqueça de gerar as tabelas:

rake db:migrate

Assim como fizemos no model Role, é necessário dizer ao Acl9 quem são os usuários, inserindo ‘acts_as_authorization_subject’ ao models/user.rb:

class User < ActiveRecord::Base
  acts_as_authentic
  acts_as_authorization_subject
end

 

Brincando com as autorizações

Bem, está tudo pronto! Aqui começa a diversão :)

No controller static_content_controller.rb, adicione no início da classe:

class StaticContentController < ApplicationController
  access_control do
    allow all
  end

  #...

Neste ponto, nada deve ter mudado (a não ser que algo tenha dado errado na instalação do Acl9), simplesmente porque estamos dando permissão de todas as actions para todos os usuários.

Vamos restringir algumas coisas:

access_control do
  allow all, :to => [:index]
  allow anonymous, :to => [:index2]
  allow logged_in, :to => [:index2, :index3]
end

Na linha allow all, :to => [:index], estamos dizendo que todos podem acessar a index. Na linha allow anonymous, :to => [:index2], somente usuários não logados podem acessar a index2, ou seja, se você estiver logado, talvez você não acesse a index2, exceto se existir uma regra explicita dizendo isso. Neste exemplo isso acontece, como você verica na última linha deste bloco: allow logged_in, :to => [:index2, :index3], claramente é notável que os usuários logados podem acessar a index2 e index3. Crie um usuário e você vai verificar que só quando você estiver logado você acessa a index3.

Ok, mas o que realmente queremos é criar regras diferentes para usuários diferentes e não apenas usuários logados e não-logados. Para isso:

access_control do
  allow all, :to => [:index]
  allow anonymous, :to => [:index2]
  allow logged_in, :to => [:index2, :index3]
  allow :admin, :to => [:index4]
end

Aqui fica interessante! Só o usuário que tiver a regra ‘admin’ vai acessar. E para fazer isso, basta associar esta regra à um usuário:

User.find(2).has_role! :admin

E se por algum motivo você precisar verificar se o usuário tem determina regra ou não, basta usar:

User.find(2).has_role? :admin
 #Retorna um boolean.

Bom, é isso.

Se tiverem dúvidas, postem nos comentários ou acessem o grupo oficial do Acl9.

Atualizado
Coloquei o projeto desenvolvido neste tutorial no GitHub:
http://github.com/lucascaton/authlogic_acl9_example/