Generator em Rails

13/04/2008


Read in english (Automatic translate wiht Google)

Olá pessoal, este será o nosso primeiro artigo sobre Rails. Em nosso desenvolvimento rails temos um plugin que utilizamos como scaffold’s customizados para tarefas que sempre utilizamos como gerar micro-CMS’s, gerador de formulários de contato, gerador de catalogo de produtos e várias outras tarefas que são comuns em nossos projetos para o grande público. Através deste mecanismo otimizamos nosso trabalho brutalmente, e grande parte deste trabalho é feito utilizando o mecanismo de generators do rails.

Uma boa fonte para entender como criar seus próprios generator’s é este artigo http://www.aidanf.net/rails/creating-your-own-generators-in-rails , é um artigo excelente e achei interessante traduzir o conteúdo para ajudar quem se interessar por esta funcionalidade.

Obs.: O artigo explica como foi criado o generator para um sistema de autenticação explicado em um outro artigo anterior, adeque o que foi feito abaixo para suas necessidades.

Criando seus próprios geradores em rails.

Neste artigo eu irei mostrar como criar o gerador que gera o código do meu artigo anterior sobre autenticação básica de usuários em rails.

Rails generatos são usados para gerar código automaticamente. Você provavelmente já utilizou para gerar controllers, models e migrations. Toda vez que você chama script/generate você está usando um gerador. Contudo é facil criar seu próprio gerador em rails. Se você encontrar-se copiando código entre aplicações você provavelmente vai achar util criar um generator para gerar o código para você.

Nota: Se seu código é adequado para ser agrupado em um plugin está é a melhor alternativa para compartilhar o código entre aplicações. Contudo existe alguns casos onde um generator é mais adequado. Generators são utils para gerar código repetitivo ou um alicerce que será muito modificado. Neste exemplo o gerador pode ser usado para gerar um sistema básico de autenticação para sua aplicação que você poderá alterar para adequar a suas necessidades.

Usualmente no rails, criar generators segue a seguinte convenção. Criar uma pasta para o gerador (nos chamamos está pasta de basic_auth). Esta pasta deve ser um diretório chamado templates. Este diretório guarda todos os código templates para seu generator. Você pode organizar os arquivos nesta pasta da forma que quiser. Mas entre estes arquivo é deve ter um arquivo chamado USAGE e outro (neste caso) basic_auth_generator.rb. O conteúdo do USAGE é impresso automaticamente quando o usuário chamar o generator passando h ou help como argumento.

O arquivo basic_auth_generator.rb( nome_do_gerador_genarator.rb ) é o arquivo principal do gerador e contém a lista de instruções para gerar o código desejado e copia-lo para seu local. A estrutura para o basic_authentication_generator é:

basic_auth
|-- USAGE
|-- basic_auth_generator.rb
`-- templates
    |-- INSTALL
    |-- controllers
    |   `-- user_controller.rb
    |-- lib
    |   `-- basic_auth.rb
    |-- migrate
    |   `-- create_users.rb
    |-- models
    |   |-- notifications.rb
    |   `-- user.rb
    |-- test
    |   |-- fixtures
    |   |   `-- users.yml
    |   |-- functional
    |   |   `-- user_controller_test.rb
    |   `-- unit
    |       `-- user_test.rb
    `-- views
        |-- notifications
        |   `-- forgot_password.rhtml
        `-- user
            |-- change_password.rhtml
            |-- forgot_password.rhtml
            |-- hidden.rhtml
            |-- login.rhtml
            |-- signup.rhtml
            `-- welcome.rhtml

Para criar o gerador nós extendemos Rails::Generator::Base e criamos o método manifesto que irá listar todos os passos para o gerador criar o código desejado. Aqui está o conteúdo do basic_auth_generator.rb

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44


class BasicAuthGenerator < Rails::Generator::Base
  def manifest
    record do |m|

      # Controller
      m.file "lib/basic_auth.rb", "lib/basic_auth.rb"
      m.file "controllers/user_controller.rb", "app/controllers/user_controller.rb" 

      # Models
      m.file "models/user.rb", "app/models/user.rb"
      m.file "models/notifications.rb", "app/models/notifications.rb"

      # Tests
      m.file "test/unit/user_test.rb", "test/unit/user_test.rb"
      m.file "test/functional/user_controller_test.rb", "test/functional/user_controller_test.rb"
      m.file "test/fixtures/users.yml", "test/fixtures/users.yml"

      # Views. 
      m.directory "app/views/notifications"
      m.directory "app/views/user"
      m.file "views/user/login.rhtml", "app/views/user/login.rhtml"
      m.file "views/user/signup.rhtml", "app/views/user/signup.rhtml"
      m.file "views/user/change_password.rhtml", "app/views/user/change_password.rhtml"
      m.file "views/user/forgot_password.rhtml", "app/views/user/forgot_password.rhtml"
      m.file "views/user/hidden.rhtml", "app/views/user/hidden.rhtml"
      m.file "views/user/hidden.rhtml", "app/views/user/welcome.rhtml"

      m.file "views/notifications/forgot_password.rhtml", "app/views/notifications/forgot_password.rhtml"


      m.migration_template "migrate/create_users.rb", "db/migrate"

      m.readme "INSTALL"
    end
  end

  def file_name
    "create_users"
  end

end

O gerador basic_auth_generator é muito simples. Tudo que ele faz é copiar cada arquivo do diretório de templates para o caminho correto. Onde

 m.file 
copia o arquivo fonte do diretório do generator para o caminho especificado quando o generator é chamado.
m.directory
cria um novo diretório .
m.migration_template
cria um novo migration. Para isso o método recebe a fonte do migration e o diretório de destino para o migration. Isso irá escolher o nome apropriado baseado nos migrations que já existem (m.migration usa o método file_name onde definimos aqui para retornar “create_users”). Nós usamos isso para dar instruções de como o usuário deverá prosseguir adiante após o generator concluir seu trabalho.

Existe uma mudanção no código do artigo anterior sobre autenticação . Existe uma dupla de métodos que precisa aparecer em nosso application controller. Mas nós não queremos que sobre-escreva o arquivo application.rb porque provavelmente terá outro código dentro. Nós podemos imprimir uma mensagem pedindo ao usuário para colocar o código desejado dentro do application_controller.rb após o gerador terminar. Nós copiamos este método do diretório lib e imprimimos a mensagem após a geração, falando ao usuário para incluir.

Então o código destinado para o application.rb que vai dentro do lib/basic_auth.rb segue abaixo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18


module BasicAuth

  def login_required
    ...
  end

  def current_user
    ...
  end

  def redirect_to_stored
    ...
  end  

end

e o usuário deve incluir este módulo em seu application_controller.rb:

1
2
3
4
5
6
7
8


require_dependency "basic_auth"

class ApplicationController < ActionController::Base
  include BasicAuth
end

No imprimimos estas instruções colocando istro dentro do arquivo INSTALL e chamando

m.readme "INSTALL"
no fim do manifest

Indo mais adiante

Não existe muita coisa neste gerador como ele apenas usa o método file para copiar os arquivos sem modifica-los. Para coisas mais complexas podemos extender Rails::Generator::NamedBase ao invés de Rails::Generator::Base. Nós podemos usar o método template para gerar código baseado em nomes passados como argumentos para o gerador.

m.template
passa o arquivo fonte para o arquivo erb e ai copia o resultado para o arquivo de destino. Assim, usando o método template você pode executar código ruby e usar o resultado em seu template gerado.

Como exemplo talvez você pode querer permitir que o usuário espcifique o nome do controler a ser gerado. Se o gerador é chamado usando ruby script/generate Account, você pode acessar o nome usando o método class_name(retornará “Account”) e file_name(retornará “account”). Voce definiria seu template de controller usando

1
2

 class <%= class_name %>Controller < ApplicationController...

e o seu manifest

1
2

 m.template "controllers/user_controller.rb", "app/controllers/#{file_name}_controller.rb"

Para aprender como fazer coisas mais complexas dê uma olhada em geradores disponíveis como o login_generator (rode gem search -r generator para obter a lista de geradores disponíveis)

Onde colocar seus gerador

Para usar seu gerador entre várias múltiplas applications você pode colocar a pasta do gerador onde o rails procure por um gerador como ~/.rails/generators na pasta home do rails ou na pasta lib/generators de sua aplicação.

Usando o gerador:

> ruby script/generate basic_auth
      create  lib/basic_auth.rb
      create  app/controllers/user_controller.rb
      create  app/models/user.rb
      create  app/models/notifications.rb
      create  test/unit/user_test.rb
      create  test/functional/user_controller_test.rb
      create  test/fixtures/users.yml
      create  app/views/notifications
      create  app/views/user
      create  app/views/user/login.rhtml
      create  app/views/user/signup.rhtml
      create  app/views/user/change_password.rhtml
      create  app/views/user/forgot_password.rhtml
      create  app/views/user/hidden.rhtml
      create  app/views/user/welcome.rhtml
      create  app/views/notifications/forgot_password.rhtml
      create  db/migrate
      create  db/migrate/001_create_users.rb
      readme  INSTALL

Download

Você pode baixar o gerador aqui: basic_auth.tar.gz , basic_auth.zip

O link original do artigo é http://www.aidanf.net/rails/creating-your-own-generators-in-rails , o blog onde foi escrito o artigo é bem interessante e sempre tem artigos que acrescentam muita coisa.

Espero que este artigo o ajude de alguma forma.

3 Comentários to “Generator em Rails”

  1. Eleudson Queiroz diz:

    Muito bom o artigo!!

    Estava precisando muito desta dica.

  2. Luiz Arão A. Carvalho diz:

    Nossa cara meus parabens estava precisando de mais dessa dica abração!

  3. Leandro diz:

    Ótimo artigo!!!

Deixe um comentário

Por problemas com spam todos os comentários são moderados.