FATEC – SP Faculdade de Tecnologia de São Paulo

Desenvolvimento ágil com Ruby on Rails

São Paulo, SP 2010

FATEC – SP Faculdade de Tecnologia de São Paulo

Desenvolvimento ágil com Ruby on Rails

Ricardo Augusto da Costa Monografia apresentada à Faculdade de Tecnologia de São Paulo para a obtenção do Grau de Tecnólogo em Processamento de Dados Prof. Orientador: Sérgio Luiz Banin

São Paulo, SP 2010

Agradecimentos:

Ao Orientador Prof. Sérgio Luiz Banin pelo incentivo e presteza no auxílio às atividades e discussões sobre o andamento e normatização desta Monografia de Conclusão de Curso. A Essy Naira Ayako Tsuda e a Marcia Cardenas pela orientação e suporte durante todo o processo de realização desta monografia. Ao colega de trabalho Tiago Pleffer pelo auxilio na pesquisa e no desenvolvimento. A empresa ADV Tecnologia e ao meu chefe Paulo Henrique Azevedo pelo apoio e incentivo, fornecendo livros e ajudando a participar de conferências e palestras sobre o tema abordado.

Índice
INTRODUÇÃO..............................................................................................................01 1 CONCEITOS BÁSICOS........................................................................................... 03 1.1 O que é Ruby ?.......................................................................................... 03 1.2 Características da linguagem Ruby........................................................... 04 1.3 O que são Ruby Gems ?............................................................................ 05 1.4 O que é MVC ?.......................................................................................... 06 1.5 O que é Rails?............................................................................................ 08 2 A LINGUAGEM RUBY........................................................................................... 09 2.1 Instalando o ruby....................................................................................... 09 2.2 Programando em ruby............................................................................... 10 2.2.1 As convenções do Ruby................................................................. 11 2.2.2 Os Arrays....................................................................................... 12 2.2.3 Retorno de métodos....................................................................... 13 2.2.4 Criando classes no ruby................................................................. 13 2.2.5 Herança em Ruby...........................................................................15 2.2.6 Polimorfismo e interfaces.............................................................. 16 2.2.7 Os Hashes...................................................................................... 17 2.2.8 Como funciona o CompareTo........................................................18 2.2.9 Metaprogramação.......................................................................... 18 2.2.10 Closures......................................................................................... 20 3 RAILS........................................................................................................................ 22 3.1 Começando a usar o rails........................................................................... 23 3.2 A primeira aplicação no rails..................................................................... 27 3.2.1 O plugin ActiveScaffold.................................................................. 30 4 CRIAÇÃO DE CADASTROS COM RAILS E ACTIVE SCAFFOLD (CRUD).... 45 4.1 Demonstração do desenvolvimento Ruby X Delphi................................. 45 4.2 Análise comparativa de criação de telas de cadastro Delphi X RubyOnRails................................................................................................................... 73 5 IMPLEMENTAÇÃO DE VALIDAÇÕES.............................................................. ..75 5.1 Análise comparativa com Delphi............................................................ ..77 6 SEGURANÇA EM RAILS..................................................................................... ..79 6.1 As principais formas de invasão na Web................................................ ..79 6.2 As proteções nativas do rails................................................................... ..80 6.3 Análise comparativa com PHP................................................................ ..81 CONCLUSÃO.............................................................................................................. ..83 BIBLIOGRAFIA.......................................................................................................... ..84

Lista de Figuras
Figura 1 - Tela inicial do cadastro de Contatos........................................................... 42 Figura 2 - A consulta é feita em qualquer campo do cadastro..................................... 42 Figura 3 - Tela de inclusão........................................................................................... 43 Figura 4 - Tela de edição.............................................................................................. 43 Figura 5 - Excluindo um registro.................................................................................. 44 Figura 6 - Tela inicial do cadastro de clientes.............................................................. 56 Figura 7 - Tela de inclusão de cadastro........................................................................ 57 Figura 8 - Consulta de Clientes.................................................................................... 57 Figura 9 - Cadastro de Clientes em Delphi...................................................................67 Figura 10 - Cadastro de Vendedores............................................................................ 69 Figura 11 - Cadastro de Produtos................................................................................. 72 Figura 12 - Exemplo de mensagem de validação de campo........................................76

Lista de Abreviaturas
1. CRUD – Create Retrive Update Delete. Significa uma tela de cadastro com as funções de Inserir, Consultar, Alterar e Excluir. 2. MVC – Model View Controller. É um padrão de arquitetura de software.que visa separar a regra de negócios da lógica de apresentação através de três camadas (modelo, visão e controlador). 3. REST - Representational State Transfer ou Transferência de Estado Representacional. É uma técnica de engenharia de software para sistemas hipermídia distribuídos como a World Wide Web 4. SOAP. Simple Object Access Protocol, ou Protocolo Simples de Acesso a Objetos, é um protocolo para troca de informações estruturadas em uma plataforma descentralizada e distribuída. 5. WSDL - Web Services Description Language (WSDL) é uma linguagem baseada em XML utilizada para descrever Web Services

CURRICULUM VITAE

Ricardo Augusto da Costa, nascido em 02/03/1989 em São Paulo–SP. Formado em Técnico de Informática na ETESP, está cursando Processamento de Dados pela Fatec-SP. Atualmente é programador na empresa ADV Tecnologia e trabalha com o desenvolvimento de sistemas ERP em ambiente web e desktop.

Resumo
Este é um trabalho que busca estudar a produtividade do desenvolvimento web através do Ruby on Rails. O foco será no desenvolvimento de sistemas baseado em CRUD. Para tal, serão elucidados os conceitos básicos do Ruby on Rails e demonstrado as principais formas de obter produtividade no desenvolvimento web de aplicações com o Ruby. Como essa linguagem ainda não é tão popular quanto outras linguagens de mercado (com Java, PHP, C#,etc), serão demonstrado o processo de instalação e configuração do ambiente. E em seguida será demonstrado um pouco da sintaxe e algumas características da linguagem, para familiarização e entendimento dos estudos que serão feitos posteriormente. Para analisar a eficiência da ferramenta será feita uma comparação entre Ruby, Delphi e PHP. Com o Delphi será estudado a criação de telas CRUD, e com o PHP será abordada a segurança web.

Abstract
This is a coursework that seeks study the productivity about web development through Ruby on Rails. The focus will be on development of CRUD based systems. For this, will be explained the basics concepts of Ruby on Rails and showed the main forms to get productivity in web applications development with Ruby Because this language is not as popular as other famous languages (eg: Java, PHP, C#, etc), will be showed the steps to install and to configure the environment. After, will be demonstrated a little of syntax and some language features, to make the language friendly and enable the understanding for the future study. To analyze the tool efficiency, will be made the comparing among Ruby, Delphi and PHP. With Delphi will be study the CRUD development and with PHP will be explained about the web safely.

1

INTRODUÇÃO

Com a popularização da internet e com a evolução da Cloud Computing, o desenvolvimento de sistemas web está virando uma tendência do mercado, devido a características importantes como: ser multiplataforma, ter facilidade na manutenção por ser centralizado, ser acessível de qualquer lugar que disponibilize de conexão com internet e um browser com os plugins necessários (Java, flash, suporte a JavaScript, etc), permitir uma infra-estrutura com um custo reduzido em relação à sistemas que rodam em ambiente desktop, facilidade no controle contra a pirataria, etc. Essas vantagens costumam atrair desenvolvedores para o ambiente web, mesmo em frente aos problemas como: segurança (que são muito comuns na web e complexos de resolver), falhas na conectividade que deixam o sistema inteiro fora do ar (falta de internet, principalmente no Brasil que ainda não tem uma conexão de boa qualidade), etc. Porém o desenvolvimento web, comparado ao desenvolvimento desktop, ainda costuma ser improdutivo, lento e trabalhoso (principalmente quando comparado com ferramentas ágeis como o Delphi). Muitos desenvolvedores web encontram dificuldade em tarefas simples e muitos desenvolvedores desktop deixam de migram para o ambiente web por considerá-lo improdutivo. Esta pesquisa sugere um alternativa de ambiente de desenvolvimento web mais eficiente que as ferramentas atuais e tão eficaz quanto, obtendo a mesma produtividade do desenvolvimento desktop sem perder as vantagens de um ambiente web.

2

Para isso será demonstrado o processo de desenvolvimento com o Ruby, desde a instalação e configuração de seus principais frameworks até o desenvolvimento de telas que justificam sua eficiência. Serão mencionados alguns conceitos da sintaxe da linguagem que não serão muito aprofundados, apenas mostrado o essencial para que se possa ter entendimento das demonstrações no desenvolvimento, onde se terá maior ênfase.

3

1 CONCEITOS BÁSICOS

1.1 O que é Ruby ? Ruby é uma Linguagem de programação interpretada, com Tipagem Dinâmica (ou seja, diferente de Java e C++, o tipo do objeto só é conhecido em runtime) e Tipagem Forte, orientada a objetos, com várias semelhanças com Perl, Python e SmallTalk. Projetada tanto para a programação em grande escala quanto para codificação rápida, tem um suporte a orientação a objetos que tem o objetivo de ser simples e prático. A linguagem, escrita em C, foi criada pelo japonês Yukihiro Matsumoto (Matz) , que aproveitou o que considerou serem as melhores idéias das outras linguagens da época (Perl and Python). Matz decidiu desenvolver sua própria linguagem porque queria uma linguagem de script que fosse mais poderosa que Perl e mais orientada a objetos que Phyton. O desenvolvimento do Ruby começou no dia 24 de fevereiro de 1993, e o primeiro “hello world” programado em Ruby rodou no verão do mesmo ano. A primeira versão alpha da linguagem foi liberada em dezembro de 1994. Ruby se tornou reconhecida no meio especializado desde que Dave Thomas e Andrew Hunt, conhecidos como "Programadores Pragmáticos", adotou-a como uma de suas linguagens preferidas e acabou por escrever um dos mais completos livros sobre a

4

linguagem, o Programming Ruby. Com o advento desta publicação, a linguagem passou a contar com uma boa fonte de iniciação e referência em inglês, aumentando conseqüentemente o número de adeptos da linguagem no Ocidente. O nome "Ruby", foi decidido durante uma sessão de bate-papo online entre Matsumoto (Matz) e Keiju Ishitsuka em 24 de fevereiro de 1993, antes que qualquer linha de código tivesse sido escrita para a linguagem.[11] Inicialmente foram propostos dois nomes: "Coral" e "Ruby", sendo esse último nome proposto escolhido mais tarde por Matz em um e-mail para Ishitsuka.[12] Mais tarde Matz descobriu que Pearl é a pedra preciosa que simboliza o mês de Junho e Ruby é a pedra que simboliza Julho, então ele concluiu que é um nome apropriado para uma linguagem que surge depois do Perl

1.2 Características da linguagem Ruby Todas as variáveis são objetos, onde até os "tipos primitivos" (tais como inteiro, real, entre outros) são classes;

Métodos de geração de código em tempo real, como os "attribute accessors";

Através do RubyGems, é possível instalar e atualizar bibliotecas com uma linha de comando, de maneira similar ao APT do Debian Linux;

5

Code blocks (blocos de código) passados como parâmetros para métodos; permite a criação de closures;

Mixins, uma forma de emular a herança múltipla;

Tipagem dinâmica, mas forte. Isso significa que todas as variáveis devem ter um tipo (fazer parte de uma classe), mas a classe pode ser alterada dinamicamente;

Ruby está disponível para diversas plataformas, como Microsoft Windows, Linux, Solaris e Mac OS X, além de também ser executável em cima da máquina virtual do Java (através doJRuby) e haver um projeto para ser executável em cima da máquina virtual Microsoft .NET, o IronRuby.

1.3 O que são Ruby Gems ? Ruby gems são bibliotecas e frameworks tais como : hibernate , spring e struts o são para Java. A diferença entre as Ruby Gems e os tradicionais frameworks Java é que as ruby Gems podem ser instaladas por um comando simples, tal como o : "apt-get install" dos debian Linux. Mais adiante será demonstrada a instalação do ruby gem, mas por hora vale lembrar que em uma maquina com o Rubygem corretamente instalado , basta fazer o seguinte comando para instalar uma biblioteca ou framework :

6

"gem install Nomedabiblioteca". Existem hoje nos repositórios do rails , mais de 12 mil gems disponíveis para as mais diversas necessidades. Além das gems existem ainda as bibliotecas que não chegam a ir para os repositórios por serem muito recentes ou por serem muito simples , essas bibliotecas podem ser baixadas e utilizadas gratuitamente de portais tais como : Ruby Forge e Ruby Application Archive (RAA), um exemplo dessas bibliotecas é o Active Scaffold que será demonstrada mais adiante para desenvolver cadastros.

1.4 O que é MVC ? Essa é uma sigla comum para a programação web e entender sua definição é fundamental para entender o que é o rails. MVC significa Model-View-Controler ou modelo-visão-controlador em português , trata-se de uma arquitetura para programação de sistemas Web baseada em três componentes principais : Model , View e Controller. Ao contrário dos tradicionais sistemas onde o programador da comandos Select , insert ou update na própria página que o internauta vê , e ainda a própria página decide qual será a próxima página a ser exibida (fluxo do sistema); os sistemas baseados no MVC tentam organizar as coisas colocando cada coisa no seu devido lugar , visando aumentar a performance , a segurança e manutenção do sistema. No MVC cada um dos componentes tem um papel claro e definido no sistema web:

7

Model: O Model reprensenta a informação (dados) da aplicação e as regras pra manipular esses dados. No caso do Rails (o meta-framework que usaremos com o ruby), o model é primeiramente usado pra gerenciar as regras de interação com uma base de dados correspondente. Na maioria dos casos uma tabela do banco de dados terá um modelo correspondente na aplicação. As regras de negócios da aplicação ficarão concentradas no Model. View: é o componente responsável pela interface da aplicação para o usuário. No rails, as views costumam ser arquivos HTML com código ruby embutido que executam tarefas relativas somente à apresentação dos dados. Controller : é o componente que recebe a requisição do usuário (GET, POST , PUT , DELETE) trata a requisição (persiste os dados no banco , valida login) e por último redireciona o usuário para a página adequada. Faz a ligação entre o model e o view. O controller é o componente mais complexo e tende a ser o mais longo (maior número de linhas de código) dentre todos os componentes do MVC. Para um exemplo simples de controle de locadoras: - O Usuário faz uma requisição de Get ao controlador „listafilmes‟ digitando no browser (ou cliando em um link) : www.locadora.com.br/listafilmes O controlador „listafilmes‟: - recebe a requisição - faz um select no banco - Carrega uma coleção na requisição com os filmes selecionados

8

- Invoca a visão (view) „listafilmes.html.erb‟ A visão listafilmes.html.erb somente exibe na tela o conteúdo da coleção de filmes carregada pelo controlador. Ao ver a página o usuário pode clicar em algum link e então mandar outra requisição para algum controlador e assim recomeçar o ciclo.

1.5 O que é Rails? Rails é o mais popular framework de MVC do ruby, e é o responsável pela expansão da linguagem ruby no mercado. Rails é uma gem desenvolvida utilizando a linguagem ruby que tem como finalidade facilitar o desenvolvimento de sistemas Web baseados na arquitetura MVC. Tornou-se muito popular por ser extremamente produtiva ao utilizar conceitos como DRY (Don't repeat yourself) e COC (Convention Over Configuration). Rails é produtivo por se basear em padrões e por isso dispensar os XMLs e/ou annotations. Ou seja, o Rails é apenas um framework MVC criado na linguagem ruby , por isso utiliza-se o termo programar em ruby on rails (programar no ruby sobre o rails).

9

2 A LINGUAGEM RUBY
2.1 Instalando o ruby Uma das grandes dificuldades do ruby on rails é possuir série vários elementos a serem instaladas, e isso demanda um bom tempo de trabalho. Como ambiente de desenvolvimento web será utilizado o Linux Ubuntu 10.04 LTS (Lucid Lynx) , rails na versão 2.3.2 e banco de dados MySQL. E para desenvolvimento Desktop será utilizado Windows XP SP2 , Delphi 7 e banco de dados Firebird. No Linux, preparando o ambiente para o Ruby On Rails: Para instalar o ruby através do console Shell, é necessário executar o comando : sudo apt-get install ruby Para instalar o interpretador de Ruby, também no console Shell, através do comando : sudo apt-get install irb Para testar se o Ruby está instalado corretamente (via shell), é executado o comando : irb Como resultado deve ser mostrado: irb(main):001:0>

10

Para sair ultilize o comando quit .

2.2 Programando em ruby Antes de iniciar a programação em ruby, alguns conceitos da linguagem: O condicional em ruby funciona do seguinte modo : if condição comando if condição comando A else comando b #ou para blocos if condição comando1 comando2 end

if condição comandoA1 comandoA2 else comandob1 comandob2 end

11

É possível ainda: comando if condição (só executa o comando se a condição for verdadeira) comando unless condição (Executa somente se a condição for falsa)

Os operadores de comparação são: == igual > maior < menor != diferente

2.2.1

As convenções do Ruby

O Ruby tem uma série de convenções para nomes de métodos, seguem as principais : #indica se uma string esta vazia 'alguma string'.empty? #todo método que retorna booleano deve terminar com ? cliente.is_restrito? #todo método que modifica efetivamente uma classe deve terminar com ! cliente.restringe!

12

# método equals deve por convenção devem ser == def ==(pessoa) return @nome == pessoa.nome end p1 = pessoa.new p2 = pessoa.new

puts p1 == p2 #exemplo de utilização do método equals 2.2.2 Os Arrays

Ao contrário de algumas linguagens, o array é efetivamente utilizado em Ruby. Seguem as principais características dos arrays Ruby :

a = Array.new #equivalente a a = []

#Métodos de fazer uma atribuição (append) em um array a << 2 a[1] = 3 #outro método de atribuição a = [2,5,'a']

#para testar: puts a[0] # será impresso „2‟

13

2.2.3

Retorno de métodos

Uma novidade no ruby é que um método pode retornar N parâmetros def MetodoDuploRet return 2,7 end puts MetodoDuploRet a = MetodoDuploRet puts a b,c = MetodoDuploRet puts b puts c 2.2.4 Criando classes no ruby

Seguem abaixo alguns exemplos de como trabalhar com classes utilizando o ruby:

#toda a classe é uma instância de class #logo uma classe é definida da seguinte maneira Pessoa = Class.new do def say puts 'hello' end end p = Pessoa.new p.say

14

Pessoa2 = Class.new #Método fora de qualquer classe vai para Object def say2 puts 'p2' end #Pessoa2.say2 self.say2 self.class Object.say2

Exemplo de classe completa com fields , getters e setters :

class Pessoa #não precisa declarar o field #setter def nome=(valor) @nome = valor end #getter def nome @nome end #jeito rápido de criar getter attr_reader :cpf #jeito rápido de criar setter attr_writer :cpf #maneira mais rápida ainda de criar getter e setter attr_accessor :idade

15

#construtor def initialize (valor) @nome = valor end #método estático class method def self.metodo_estatico puts 'isto é um método estático' end end

2.2.5

Herança em Ruby

class Animal def come puts 'comendo' end private def metodo_privado puts 'este é privado' end end class Peixe < Animal end p = Peixe.new p.come p.metodo_privado # Cuidado. Aqui daria erro de execução porque o método é privado

16

2.2.6

Polimorfismo e interfaces

#duck typing #não precisa de interface #ruby não tem interface

class PatoEstranho def faz_quack puts 'queck' end end class PatoNormal def faz_quack puts 'quack' end end class CriadorDePato def castiga(pato) pato.faz_quack end end pe = PatoEstranho.new pn = PatoNormal.new c = CriadorDePato.new c.castiga pe c.castiga pn

17

2.2.7

Os Hashes

Outra estrutura de coleção muito importante no ruby e utilizada no rails são os hashes (semelhantes ao Map do Java).

Seguem exemplos de utilização de hashes : class Carro attr_accessor :dono def initialize (nomedono) @dono = nomedono end end c1 = Carro.new "Ricardo" c2 = Carro.new "mariana" #criando um hash detran = {:"ABC1122" => c1, :"EBE5774" => c2} puts detran[:"EBE5774"].dono def transfere(args) puts "transferindo #{args[:valor]} para a conta #{args[:n]}" end transfere({:valor => 100, :n => 234 }) #mais simples transfere :valor => 100, :n => 234

18

2.2.8

Como funciona o CompareTo

#No ruby por convenção o compareTo é <=> #Exemplo de utilização de compareTo : class Cachorro attr_accessor :peso def <=> (outro) return 0 if peso == outro.peso return 1 if peso > outro.peso return -1 if peso < outro.peso end end a.equal? b #o mesmo que equals == a.eqr? #o mesmo que igual pelo hashcode

2.2.9

Metaprogramação

No Ruby é possível alterar ou adicionar métodos em tempo de execução porque todo código Ruby é executado – não há separação entre fases de compilação e runtime, cada linha de código é executado contra um self particular.

class Aluno end

19

class Professor def ensina aluno def aluno.responde # aqui é possível adicionar um método à classe aluno puts 'agora eu sei tudo' end end end a = Aluno.new #a.responde p = Professor.new p.ensina a a.responde #exemplo de metaprogramação - adicionar um método em tempo de execução class Carro end class Oficina def turbina(carro) def carro.turbo puts 'turbo ligado' end end end c = Carro.new #c.turbo o = Oficina.new o.turbina c c.turbo

20

2.2.10 Closures O Ruby também permite passar métodos como parâmetros: #exemplo básico de closure def metodo puts "linha 1" yield #aqui vai entrar o código do bloco que vier como parâmetro end

metodo do # isso é o mesmo que chamar metodo passando um trecho de código #como parâmetro puts "linha 2" #isso é parâmetro end

#exemplo mais complexo de closure def metodo2 puts "linha B1" yield "ricardo" , "adv" # O código que vier aqui vai receber estes dois parâmetros yield("facilita" , "facilitador") # Também pode se usar parênteses end # como funciona: # o & permite passar um bloco como param para utilizar o call # o yield e o método call são equivalentes # embora o call fique mais claro a convenção é utilizar o yield

21

def met (&metodo) metodo.call # o mesmo que yield end met do puts 'teste' end # o mesmo que o anterior mas utilizando uma variável para guardar o bloco #aqui não é preciso do & pois passa uma variável com o bloco

def met2 (met) met.call end #atribuindo um bloco a uma variável bloco = lambda { puts 'teste2' } bloco.call # execução para teste met2(bloco) # passando por parâmetro

22

3 RAILS
Conforme já foi mostrado antes, o Rails, é um framework desenvolvido em Ruby e de código aberto assim como Ruby. Leva em sua arquitetura o design pattern "MVC" (Model-View-Controller). O modelo MVC oferece vantagens significativas no desenvolvimento de aplicativos, através da separação das camadas, possibilitando implementar com maior facilidade e clareza questões programáticas importantes como a persistência de dados, controle de segurança, comunicação em rede e fluxo de visualização.

O Rails pode ser considerado um "meta-framework" porque é uma junção de vários componentes:

Active Record O Active Record é uma camada de mapeamento objeto-relacional (objectrelational mapping layer), responsável pela interoperabilidade entre a aplicação e o banco de dados e pela abstração dos dados. Action Pack Compreende o Action View (geração de visualização de usuário, como HTML, XML, JavaScript, entre outros) e o Action Controller (controle de fluxo de negócio). Action Mailer O Action Mailer é um framework responsável pelo serviço de entrega e até mesmo de recebimento de e-mails. É relativamente pequeno e simples, porém poderoso

23

e capaz de realizar diversas operações apenas com chamadas de entrega de correspondência. Active Support Active Support é uma coleção de várias classes e extensões de bibliotecas padrões, que foram consideradas úteis para aplicações em Ruby on Rails. Action WebServices Provê uma maneira de publicar APIs interoperáveis com o Rails, sem a necessidade de perder tempo dentro de especificações de protocolo. Implementa WSDL e SOAP. O Action Web Service não estará mais presente na versão 2.0 no Rails, visto que o mesmo está voltando-se para a utilização do modelo REST. Mesmo assim, aos ainda interessados em utilizá-lo, será possível fazê-lo através da instalação de um plugin.

3.1 Começando a usar o rails A instalação do Rails é feita da seguinte forma: Primeiro é necessário instalar o Ri (testador do ruby) e o rdoc (gerador de documentação do ruby semelhante ao Javadoc do Java)

No Console digitando: sudo apt-get install rdoc ri

24

Depois instalando o programa que gerencia as gems (lembram das gems) do ruby. Este não vale a pena instalar via apt-get install porque a versão nos repositórios debian tem alguns bugs.

No Console digitando: cd /usr/local wget http://rubyforge.org/frs/download.php/60718/rubygems-1.3.5.tgz tar xvzf rubygems-1.3.5.tgz cd rubygems-1.3.5/ sudo ruby setup.rb

Feito isso o comando gem1.8 gera em qualquer pasta da máquina o help do Gem: ricardo@programacao1:/usr/local$ gem1.8 Gerando a seguinte documentação:

RubyGems is a sophisticated package manager for Ruby. This is a basic help message containing pointers to more information. Usage: gem -h/--help gem -v/--version gem command [arguments...] [options...]

25

Examples: gem install rake gem list --local gem build package.gemspec gem help install Further help: gem help commands gem help examples gem help platforms gem help <COMMAND> Further information: http://rubygems.rubyforge.org list all 'gem' commands show some examples of usage show information about platforms show help on COMMAND

(e.g. 'gem help install')

para não precisar digitar „gem1.8‟ , cria-se um link simbólico: sudo ln -s /usr/bin/gem1.8 /usr/bin/gem Agora o comando „gem‟ deve funcionar igual a „gem1.8‟. Embora pareça, o rubygems não está instalado ainda, faltam bibliotecas que ele utiliza em C++ . No terminal execute os comandos: sudo apt-get install libopenssl-ruby sqlite3 build-essential libsqlite3-dev libmysqlclient15-dev ruby-dev ruby1.8-dev

26

Para todos os exemplos a seguir, será utilizado o mysql , então é preciso instalar caso ainda não esteja (pelo terminal): sudo apt-get install mysql-server E um client para mexer no mysql: sudo apt-get install mysql-query-browser Agora instalando as gems necessárias ao rails: sudo gem install rails –version “2.3.2” sudo gem install mongrel sudo gem install mysql Agora executando um comando que lista as gems instaladas : gem list --local

A lista retornada deve ser :

*** LOCAL GEMS *** actionmailer (2.3.2) actionpack (2.3.2) activerecord (2.3.2) activeresource (2.3.2) activesupport (2.3.2) cgi_multipart_eof_fix (2.5.0) daemons (1.1.0)

27

fastthread (1.0.7) gem_plugin (0.2.3) mongrel (1.1.5) mysql (2.8.1) rails (2.3.2) rake (0.8.7)

O rails já está instalado, agora é necessário uma IDE. Uma muito utilizada para o rails, atualmente, é o aptana: Para instalar é necessário baixar o tar.gz de acordo com a arquitetura do ambiente em http://www.aptana.com/radrails/download/ Copiando e descompactando a pasta em /usr/local, depois executando o comando : sudo ./Aptanastudio # o aptana será aberto. Obs: Antes de executar o aptana é necessário ter o java instalado.

3.2 A primeira aplicação no rails Com o ambiente instalado e configurado, para iniciar o desenvolvimento de um projeto pelo console Shell, são executados (para criar as pastas do projeto): cd /home mkdir fontes mkdir rails cd /home/fontes/rails

28

Agora para criar um projeto cujo banco de dados é mysql (via Shell): rails agenda -d mysql Feito isso o rails vai criar uma pasta „agenda‟ com uma determinada estrutura de diretórios dentro. A finalidade dos diretórios está descrita abaixo:

Readme – arquivo com instruções de uso; Rakefile – script de construção; app/ – Dentro dessa pasta estão os arquivos da estrutura MVC – (Model, View e Controller); components/ – componentes reutilizáveis; config/ – parâmetros de configurações tanto do projeto quanto do banco de dados; db/ – Informações sobre o esquema e as migrations geradas para modificar o banco de dados; doc/ – Documentação auto gerada, utilizando o Rdoc, lib/ – Código compartilhado códigos que não podemos adicionar a uma um modelo, view ou controller, algo como um gerador de arquivos pdf. log/ – documentos de log produzidos pelo seu aplicativo; public/ – Diretório acessível pela Web. É a pasta onde o HTTP server utiliza pra rodar o aplicativo;

29

script/ – Scripts utilitários, onde estão os programas utilizados pelos desenvolvedores Rails; test/ – Utilitários de testes, onde são escritos os teste funcionais, testes de integração, fixtures e simulações; tmp/ – Arquivos temporários utilizados e gerados em tempo de execução do seu aplicativo; vendor/ – Código importado onde são colocados os plugins utilizados pela aplicação, código de terceiros. As pastas app/ e db/ é onde fica quase toda a aplicação, são as pastas mais alteradas em um projeto. Todo projeto rails tem alguns scripts padrões na sua pasta raiz , então ao digitar (no prompt de comandos): cd agenda Entrará na raiz da aplicação e podem ser utilizados os seguintes scripts (esses scripts são executados no shell do Linux dentro do diretório do projeto) : script/server start - Inicia a aplicação no browser (põe no ar), para parar basta utilizar Ctrl +C. rake db:create:all - cria as bases de dados do projeto , as bases são definidas no arquivo config/database.yml rake db:migrate - atualiza a estrutura do banco com as tabelas criadas no projeto

30

rake db:migrate:down -Version xxxx - Volta o banco de dados para uma versão específica. Script/generate artefato* nome_do_artefato - gera diversos artefatos* , são alguns deles : Migration - Arquivo que modifica os bancos de dados da aplicação. Model - Gera automaticamente uma migration para criar o model em questão e um model no sistema. Models são classes do modelo de negócio ( Clientes , Produtos e etc...) Controller - Gera um controlador automaticamente.

3.2.1 O plugin ActiveScaffold O Active Scaffold é um dos plugins responsáveis pelo ganho de produtividade que o RubyOnRails oferece, e que o torna uma opção interessante para o desenvolvimento web. O active scaffold pode ser instalado com um comando na pasta do projeto rails, mas antes (apenas na primeira vez) é necessário instalar uma dependência, o git-core : apt-get install git-core Agora, com o git-core instalado, o seguinte comando instala o plugin do Active Scaffold no projeto:
script/plugin install git://github.com/activescaffold/active_scaffold.git -r rails-2.3

31

Depois de instalado , prepara-se a aplicação para utilizá-lo , para isto é necessário tomar os seguintes passos :  Abrir o Aptana (via shell script, para abrir como root) e adicionar o projeto nele: no prompt de comandos, no diretório onde se encontra o Aptana, executa-se o comando sudo ./AptanaRadRails Após aberto a IDE, para adicionar um projeto, em File -> New -> Rails Project , selecione a opção „Create project from existing source‟ e busque a pasta onde o projeto foi criado anteriormente via shell (pelo comando „rails agenda -d mysql‟)  Preparar todas as views para que elas importem o CSS e Javascript necessário para o ActiveScaffold, para isso criam-se um template de aplicação na pasta app/view/layouts e um template de CSS na pasta public/stylesheets: Na pasta app/view/layouts cria-se o arquivo application.html.erb com o seguinte conteúdo:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <title>Contatos</title>

32

<%= javascript_include_tag :defaults %> <%= active_scaffold_includes %> <%= stylesheet_link_tag 'default.css' %>

</head> <body> </body> </html>

E na pasta public/stylesheets cria-se o arquivo default.css com o seguinte conteúdo (esse conteúdo é apenas sugestivo, é o layout padrão da aplicação e pode ser editado conforme a necessidade do projeto):

a{ text-decoration: none; color:#AAAAAA; font-weight:bold;

}

a:hover { color: #AFD0F5;

}

33

Agora se adiciona o active scaffold ao controlador do modelo que será criado o cadastro:

Por exemplo, ao criar um cadastro de contatos para o projeto da Agenda: - como será o primeiro cadastro, é necessário criar o banco de dados, mas antes é preciso definir a senha do mysql no projeto. Isso é feito dentro do arquivo /config/database.yml, no campo password conforme o exemplo (via aptana): development: adapter: mysql encoding: utf8 reconnect: false database: agenda_development pool: 5 username: root password: 123456 socket: /var/run/mysqld/mysqld.sock # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: mysql encoding: utf8 reconnect: false database: agenda_test pool: 5 username: root password: 123456 socket: /var/run/mysqld/mysqld.sock production: adapter: mysql

34

encoding: utf8 reconnect: false database: agenda_production pool: 5 username: root password: 123456 socket: /var/run/mysqld/mysqld.sock Aqui a aplicação já está configurada para utilizar o ActiveScaffold. Agora se cria o banco de dados da aplicação (via shell script): rake db:create:all Cria-se o modelo (via shell script:
script/generate model contato nome:string idade:integer fone:string endereco:string

Cria-se a migration, que criará a tabela no banco de dados (via shell script): rake db:migrate Cria-se o controller (via shell script): script/generate controller contatos #aqui é necessário acrescentar a letra „s‟ no # final (por padrão do rails) No controller criado, é necessário adicionar o seguinte código, dentro da classe já existente (via aptana) : obs: o controller fica na pasta app/controllers e, nesse caso, chama contatos_controller.rb active_scaffold :contato do | config |

35

end Para testar basta acessar a seguinte URL (pelo browser): http://localhost:3000/contatos/ Porém alguns ajustes ainda podem ser feito, como: Definir o idioma da aplicação para português. Incluir o arquivo de localização para o Brasil do ActiveScaffold. Encaminhar o chamado de rota do controller para o ActiveScaffold para resolver o erro na ordenação. Para realizar esses ajustes: Para definir o idioma é necessário abrir o arquivo /config/environment.rb e adicionar a linha : config.i18n.default_locale = :pt Agora para adicionar o arquivo de português na aplicação basta salvar um arquivo chamado pt.yml na pasta /config/locales com o seguinte conteúdo:
pt: # formatos de data e hora active_scaffold: add: "Add" add_existing: "Associar existente" are_you_sure: "Você tem certeza?" cancel: "Cancelar" click_to_edit: "Click para editar" close: "Fechar" create: "Inserir" create_model: "Inserir {{model}}"

36

create_another: "Inserir Outro" created_model: "{{model}} Inserido" create_new: "Inserir Novo" customize: "Customizar" delete: "Deletar" deleted_model: "{{model}} Deletado" delimiter: "Delimiter" download: "Download" edit: "Editar" export: "Export" filtered: "(Filtrado)" found: "Encontrados" hide: "Ocultar" live_search: "Localizar" loading…: "Carregando…" nested_for_model: "{{nested_model}} for {{parent_model}}" next: "Próximo" no_entries: "Nenhum registro encontrado" omit_header: "Ocultar cabeçalho" options: "Opções" pdf: "PDF" previous: "Anterior" print: "Imprimir" refresh: "Atualizar" remove: "Remover" remove_file: "Remover ou Substituir arquivo" replace_with_new: "Substituir com o novo" revisions_for_model: "Revisions for {{model}}" reset: "Limpar" saving…: "Salvando…" search: "Localizar" search_terms: "Buscar por" _select_: "-" show: "Exibir" show_model: "Exibindo {{model}}" _to_ : " to " update: "Alterar" update_model: "Alterando {{model}}" udated_model: "Updated {{model}}"

37

percentage_example: "Ex. 10%" usa_phone_example: "Ex. 111-333-4444" usa_money_example: "Ex. 1.333" usa_zip_example: "Ex. 88888-333" ssn_example: "Ex. 555-22-3333"

# error_messages internal_error: "Request Failed (code 500, Internal Error)" version_inconsistency: "Version inconsistency - this record has been modified since you started editing it."

date: formats: default: "%d/%m/%Y" short: "%d de %B" long: "%d de %B de %Y"

day_names: [Domingo, Segunda, Terça, Quarta, Quinta, Sexta, Sábado] abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb] month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro] abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez] order: [ :day, :month, :year ]

time: formats: default: "%A, %d de %B de %Y, %H:%M hs" short: "%d/%m, %H:%M hs" long: "%A, %d de %B de %Y, %H:%M hs" am: '' pm: ''

# date helper distanci em palavras datetime: distance_in_words: half_a_minute: 'meio minuto' less_than_x_seconds:

38

one: 'menos de 1 segundo' other: 'menos de {{count}} segundos'

x_seconds: one: '1 segundo' other: '{{count}} segundos'

less_than_x_minutes: one: 'menos de um minuto' other: 'menos de {{count}} minutos'

x_minutes: one: '1 minuto' other: '{{count}} minutos'

about_x_hours: one: 'aproximadamente 1 hora' other: 'aproximadamente {{count}} horas'

x_days: one: '1 dia' other: '{{count}} dias'

about_x_months: one: 'aproximadamente 1 mês' other: 'aproximadamente {{count}} meses'

x_months: one: '1 mês' other: '{{count}} meses'

about_x_years: one: 'aproximadamente 1 ano' other: 'aproximadamente {{count}} anos'

over_x_years: one: 'mais de 1 ano' other: 'mais de {{count}} anos' prompts:

39

year: "Ano" month: "Mês" day: "Dia"

hour: "Hora" minute: "Minuto" second: "Segundos"

# numeros number: format: precision: 3 separator: ',' delimiter: '.' currency: format: unit: 'R$' precision: 2 format: '%u %n' separator: ',' delimiter: '.' percentage: format: delimiter: '.' precision: format: delimiter: '.' human: format: precision: 1 delimiter: '.' storage_units: format: "%n %u" units: byte: one: "Byte" other: "Bytes" kb: "KB" mb: "MB" gb: "GB"

40

tb: "TB"

# Used in array.to_sentence. support: array: words_connector: ", " two_words_connector: " e " last_word_connector: " e "

# Active Record activerecord: errors: template: header: one: "Não foi possível gravar {{model}}: 1 erro" other: "Não foi possível gravar {{model}}: {{count}} erros." body: "Por favor, verifique o(s) seguinte(s) campo(s):" messages: inclusion: "não está incluído na lista" exclusion: "não está disponível" invalid: "não é válido" confirmation: "não está de acordo com a confirmação" accepted: "deve ser aceito" empty: "não pode ficar vazio" blank: "não pode ficar em branco" too_long: "é muito longo (máximo: {{count}} caracteres)" too_short: "é muito curto (mínimo: {{count}} caracteres)" wrong_length: "não possui o tamanho esperado ({{count}} caracteres)" taken: "já está em uso" not_a_number: "não é um número" greater_than: "deve ser maior do que {{count}}" greater_than_or_equal_to: "deve ser maior ou igual a {{count}}" equal_to: "deve ser igual a {{count}}" less_than: "deve ser menor do que {{count}}" less_than_or_equal_to: "deve ser menor ou igual a {{count}}" odd: "deve ser ímpar" even: "deve ser par"

41

Resolvido o problema idiomático , é necessário criar uma rota para a função “procurar” funcionar. Para isso, no arquivo /config/routes.rb adiciona-se no começo do arquivo, porém após a linha „ActionController::Routing::Routes.draw do |map|‟, o seguinte: map.resources :contatos, :active_scaffold => true Para testar novamente, acesse a url : http://localhost:3000/contatos/ Para definir a ordem das colunas do grid e quais colunas aparecerão é necessário definir no controlador uma matriz com as colunas e a ordem que serão exibidas. Abrindo o arquivo contatos_controller.rb, adicione o seguinte : active_scaffold :contato do | config | config.columns = [:nome :endereco :fone :idade ] end

Para alterar o label dos campos que são exibidos ao usuário e colocar uma paginação no grid, também no controller, adiciona-se o código:

active_scaffold :contato do | config | config.list.columns = [:nome, :endereco, :fone, :idade ] config.list.per_page = 5 #adiciona paginação a cada 5 registros config.columns[:nome].label = "Nome" config.columns[:endereco].label = "Endereço" config.columns[:fone].label = "Telefone" config.columns[:idade].label = "Idade" end

42

Na edição do cadastro, para não aparecer uma descrição estranha como por exemplo Alterando #<Contato:0x7f1a428d9cb8> , é necessário adicionar o seguinte código no model (colocar o código via aptana dentro da classe „Contato‟, no model „contato.rb‟ da pasta models): def to_s nome end

Feito isso os cadastros ficam como os do exemplo a seguir:

Figura 1 - Tela inicial do cadastro de Contatos

Figura 2 - A consulta é feita em qualquer campo do cadastro

43

Figura 3 - Tela de inclusão

Figura 4 - tela de edição

44

Figura 5 - excluindo um registro

45

4 CRIAÇÃO DE CADASTROS COM RAILS E ACTIVE SCAFFOLD (CRUD)

4.1 Demonstração do desenvolvimento Ruby X Delphi Para demonstrar a produtividade do RubyOnRails na criação de sistemas baseados em telas CRUD será feito um comparativo com o desenvolvimento em delphi. Os requisitos serão os seguintes: Criar cadastros com as funções de incluir, consultar, alterar e excluir registros. (Clientes , produtos e vendedores). Em RubyOnRais, com o plugin ActiveScaffold: Antes de definir os passos para criar os cadastros vale lembrar que a qualquer momento pode ser iniciada a aplicação com o comando shell: script/server start E então ela poderá ser acessada na url http://localhost:3000/Nome_controller , onde Nome_controller é o nome de algum controller da aplicação. Por exemplo, para acessar o cadastro de clientes: http://localhost:3000/clientes São tomados os seguintes passos:  Criar o projeto

46

No shell: su #para trabalhar logado como root cd /home/fontes/rails rails vendas -d mysql

Adicionar o projeto no Aptana Para abrir o aptana como root: No shell, mas em outra instância do terminal (porque ela ficará presa

durante a execução do aptana): su #para trabalhar logado como root cd /usr/local/Aptana\ RadRails/ #diretório do Aptana ./AptanaRadRails

Adicionar o projeto na IDE  Adicionar o plugin do ActiveScaffold ao projeto

No shell (): cd /home/fontes/rails/vendas/ #para entrar no diretório do projeto script/plugin install git://github.com/activescaffold/active_scaffold.git -r rails-2.3

47

Criar os templates de view e css (no Aptana):

Na pasta app/views/layouts criar o arquivo „application.html.erb‟ com o conteúdo:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title>Vendas</title> <%= javascript_include_tag :defaults %> <%= active_scaffold_includes %> <%= stylesheet_link_tag 'default.css' %> </head> <body> <%= yield %> </body> </html>

Na pasta public/stylesheets criar o arquivo „default.css‟ com o conteúdo:
a{ text-decoration: none; color:#AAAAAA; font-weight:bold;

}

a:hover { color: #AFD0F5; }

Definir a senha do MySql (no Aptana)

No arquivo config/database.yml colocar a senha no campo „password‟

48

# MySQL. Versions 4.1 and 5.0 are recommended. # # Install the MySQL driver: # gem install mysql # On Mac OS X: # sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql # On Mac OS X Leopard: # sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysqlconfig=/usr/local/mysql/bin/mysql_config # This sets the ARCHFLAGS environment variable to your native architecture

# On Windows: # gem install mysql # # # # And be sure to use new-style password hashing: # http://dev.mysql.com/doc/refman/5.0/en/old-client.html development: adapter: mysql encoding: utf8 reconnect: false database: vendas_development pool: 5 username: root password: 123456 socket: /var/run/mysqld/mysqld.sock Choose the win32 build. Install MySQL and put its /bin directory on your path.

# Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: mysql encoding: utf8 reconnect: false database: vendas_test pool: 5 username: root password: 123456 socket: /var/run/mysqld/mysqld.sock

49

production: adapter: mysql encoding: utf8 reconnect: false database: vendas_production pool: 5 username: root password: 123456 socket: /var/run/mysqld/mysqld.sock

Criar o banco de dados

No shell: rake db:create:all  Ajustar o idioma no projeto(no aptana) no arquivo /config/environment.rb , adicionar a linha: config.i18n.default_locale = :pt criar um arquivo chamado pt.yml na pasta /config/locales com o conteúdo:
pt: # formatos de data e hora active_scaffold: add: "Add" add_existing: "Associar existente" are_you_sure: "Você tem certeza?" cancel: "Cancelar" click_to_edit: "Click para editar" close: "Fechar" create: "Inserir" create_model: "Inserir {{model}}"

50

create_another: "Inserir Outro" created_model: "{{model}} Inserido" create_new: "Inserir Novo" customize: "Customizar" delete: "Deletar" deleted_model: "{{model}} Deletado" delimiter: "Delimiter" download: "Download" edit: "Editar" export: "Export" filtered: "(Filtrado)" found: "Encontrados" hide: "Ocultar" live_search: "Localizar" loading…: "Carregando…" nested_for_model: "{{nested_model}} for {{parent_model}}" next: "Próximo" no_entries: "Nenhum registro encontrado" omit_header: "Ocultar cabeçalho" options: "Opções" pdf: "PDF" previous: "Anterior" print: "Imprimir" refresh: "Atualizar" remove: "Remover" remove_file: "Remover ou Substituir arquivo" replace_with_new: "Substituir com o novo" revisions_for_model: "Revisions for {{model}}" reset: "Limpar" saving…: "Salvando…" search: "Localizar" search_terms: "Buscar por" _select_: "-" show: "Exibir" show_model: "Exibindo {{model}}" _to_ : " to " update: "Alterar" update_model: "Alterando {{model}}" udated_model: "Updated {{model}}"

51

percentage_example: "Ex. 10%" usa_phone_example: "Ex. 111-333-4444" usa_money_example: "Ex. 1.333" usa_zip_example: "Ex. 88888-333" ssn_example: "Ex. 555-22-3333"

# error_messages internal_error: "Request Failed (code 500, Internal Error)" version_inconsistency: "Version inconsistency - this record has been modified since you started editing it."

date: formats: default: "%d/%m/%Y" short: "%d de %B" long: "%d de %B de %Y"

day_names: [Domingo, Segunda, Terça, Quarta, Quinta, Sexta, Sábado] abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb] month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro] abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez] order: [ :day, :month, :year ]

time: formats: default: "%A, %d de %B de %Y, %H:%M hs" short: "%d/%m, %H:%M hs" long: "%A, %d de %B de %Y, %H:%M hs" am: '' pm: ''

# date helper distanci em palavras datetime: distance_in_words: half_a_minute: 'meio minuto'

52

less_than_x_seconds: one: 'menos de 1 segundo' other: 'menos de {{count}} segundos'

x_seconds: one: '1 segundo' other: '{{count}} segundos'

less_than_x_minutes: one: 'menos de um minuto' other: 'menos de {{count}} minutos'

x_minutes: one: '1 minuto' other: '{{count}} minutos'

about_x_hours: one: 'aproximadamente 1 hora' other: 'aproximadamente {{count}} horas'

x_days: one: '1 dia' other: '{{count}} dias'

about_x_months: one: 'aproximadamente 1 mês' other: 'aproximadamente {{count}} meses'

x_months: one: '1 mês' other: '{{count}} meses'

about_x_years: one: 'aproximadamente 1 ano' other: 'aproximadamente {{count}} anos'

over_x_years: one: 'mais de 1 ano' other: 'mais de {{count}} anos'

53

prompts: year: "Ano" month: "Mês" day: "Dia"

hour: "Hora" minute: "Minuto" second: "Segundos"

# numeros number: format: precision: 3 separator: ',' delimiter: '.' currency: format: unit: 'R$' precision: 2 format: '%u %n' separator: ',' delimiter: '.' percentage: format: delimiter: '.' precision: format: delimiter: '.' human: format: precision: 1 delimiter: '.' storage_units: format: "%n %u" units: byte: one: "Byte" other: "Bytes" kb: "KB" mb: "MB"

54

gb: "GB" tb: "TB"

# Used in array.to_sentence. support: array: words_connector: ", " two_words_connector: " e " last_word_connector: " e "

# Active Record activerecord: errors: template: header: one: "Não foi possível gravar {{model}}: 1 erro" other: "Não foi possível gravar {{model}}: {{count}} erros." body: "Por favor, verifique o(s) seguinte(s) campo(s):" messages: inclusion: "não está incluído na lista" exclusion: "não está disponível" invalid: "não é válido" confirmation: "não está de acordo com a confirmação" accepted: "deve ser aceito" empty: "não pode ficar vazio" blank: "não pode ficar em branco" too_long: "é muito longo (máximo: {{count}} caracteres)" too_short: "é muito curto (mínimo: {{count}} caracteres)" wrong_length: "não possui o tamanho esperado ({{count}} caracteres)" taken: "já está em uso" not_a_number: "não é um número" greater_than: "deve ser maior do que {{count}}" greater_than_or_equal_to: "deve ser maior ou igual a {{count}}" equal_to: "deve ser igual a {{count}}" less_than: "deve ser menor do que {{count}}" less_than_or_equal_to: "deve ser menor ou igual a {{count}}" odd: "deve ser ímpar" even: "deve ser par"

55

Nesse ponto o projeto já está criado e configurado, é necessário criar então os cadastros de cliente, vendedor e produto A partir daqui o procedimento se repetirá para cada cadastro do sistema  Cadastro de clientes Criar o model cliente No shell: script/generate model cliente nome:string datanasc:date fone:string endereco:string cep:string bairro:string cidade:string estado:string numcli:integer rg:string Criar a tabela clientes no banco No shell: rake db:migrate Criar o controller No shell: script/generate controller clientes #aqui é necessário acrescentar a letra „s‟ no final # (por padrão do rails)  No controller criado, é necessário adicionar o seguinte código (no aptana) : active_scaffold :clientes do | config | end Adicionar uma rota no arquivo /config/routes.rb (no aptana): map.resources :clientes, :active_scaffold => true

56

Definir os campos do grid (no aptana) Editar o controller, acrescentando na classe:

active_scaffold :contato do | config | #isso já foi inserido no passo 8.4 config.columns = [:numcli , :nome, :rg, :datanasc, :fone, :endereco, :cep, :bairro , :cidade, :estado ] config.list.per_page = 10 #adiciona paginação a cada 10 registros end #isso já foi inserido no passo 8.4

Definir a descrição na edição do registro (no aptana) Editar o model, acrescentando na classe: def to_s nome end

Aqui o Cadastro está criado com as funções de inclusão, consulta (por qualquer campo do cadastro), alteração e exclusão.

Figura 6 - tela inicial do cadastro de clientes

57

Figura 7 - Tela de inclusão de cadastro

Figura 8 - Consulta de Clientes

Cadastro de vendedores Criar o model vendedor

58

No shell: script/generate model vendedor nome:string datanasc:date fone:string endereco:string cep:string bairro:string cidade:string estado:string numvnd:integer comissao:float Criar a tabela vendedores no banco No shell: rake db:migrate Criar o controller No shell: script/generate controller vendedors No controller criado , é necessário adicionar o seguinte código (no aptana) : active_scaffold :vendedors do | config | end Adicionar uma rota no arquivo /config/routes.rb (no aptana): map.resources :vendedors, :active_scaffold => true

Definir os campos do grid (no aptana) Editar o controller, acrescentando na classe:

59

active_scaffold :vendedors do | config | #isso já foi inserido no passo 9.4 config.columns = [:numvnd , :nome, :datanasc, :fone, :endereco, :cep, :bairro , :cidade, :estado , :comissao] config.list.per_page = 10 #adiciona paginação a cada 10 registros end #isso já foi inserido no passo 9.4

Definir a descrição na edição do registro (no aptana) Editar o model, acrescentando na classe: def to_s nome end

Cadastro de produtos Criar o model produto No shell: script/generate model produto descricao:string preco:float

codigo:string icms:float ipi:float Criar a tabela produtos no banco No shell: rake db:migrate Criar o controller No shell: script/generate controller produtos

60

No controller criado , é necessário adicionar o seguinte código (no aptana) : active_scaffold :produtos do | config | end

Adicionar uma rota no arquivo /config/routes.rb (no aptana): map.resources :produtos, :active_scaffold => true

Definir os campos do grid (no aptana) Editar o controller, acrescentando na classe:

active_scaffold :produtos do | config | #isso já foi inserido no passo 9.4 config.columns = [:codigo , :descricao, :preco, :icms, :ipi] config.list.per_page = 10 #adiciona paginação a cada 10 registros end #isso já foi inserido no passo 9.4

Definir a descrição na edição do registro (no aptana) Editar o model, acrescentando na classe: def to_s descricao end

61

Criar um menu de navegação:

No arquivo /app/views/layoutsaplication.html.erb adicionar os links para cada cadastro. O arquivo ficará assim:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <%= stylesheet_link_tag 'default.css' %> <title>Agenda</title> <%= javascript_include_tag :defaults %> <%= active_scaffold_includes %> </head> <body>

<%= link_to 'Clientes' , clientes_url %> <%= link_to 'Vendedores' , vendedors_url %> <%= link_to 'Produtos' , produtos_url %>

<%= yield %>

</body> </html>

Preparar a Index Deletar o arquivo index.html da pasta /public/ No arquivo /config/routes.rb: Procure por:

# map.root :controller => “welcome” Descomente essa linha e modifique para:

62

map.root :controller => "clientes"

Iniciar a aplicação(este procedimento pode ser feito a qualquer momento para testar a aplicação, é necessário apenas alterar a url colocando o nome de algum controller da aplicação. Por exemplo: http://localhost/3000/clientes ):

No Shell: script/server start No Browser: acesse a url: http://localhost/3000/

Em Delphi:  Criar o banco de dados, as tabelas, os generators e os triggers que alimentam os id‟s de cada tabela

/* tabela de cliente */ create table clientes( id integer primary key, nome varchar(255), datanasc date, fone varchar(255), endereco varchar(255), cep varchar(25), bairro varchar(30),

63

cidade varchar(30), estado varchar(2), numcli integer, rg varchar(25) );
CREATE GENERATOR GN_CLIENTES;

SET TERM ^; CREATE TRIGGER INSCLI FOR CLIENTES ACTIVE BEFORE INSERT AS BEGIN IF ((NEW.ID IS NULL) OR (NEW.ID = 0)) THEN NEW.ID = GEN_ID(GN_CLIENTES,1); END ^ SET TERM ; ^

/* TABELA DE VENDEDORES */

create table vendedores( id integer primary key, nome varchar(255), datanasc date, fone varchar(255), endereco varchar(255), cep varchar(25), bairro varchar(30), cidade varchar(30), estado varchar(2), numvnd integer, comissao double precision );

CREATE GENERATOR GN_VENDEDORES;

64

SET TERM ^; CREATE TRIGGER INSVND FOR VENDEDORES ACTIVE BEFORE INSERT AS BEGIN IF ((NEW.ID IS NULL) OR (NEW.ID = 0)) THEN NEW.ID = GEN_ID(GN_VENDEDORES,1); END ^ SET TERM ; ^

/* TABELA DE PRODUTOS */

create table produtos( id integer primary key, descricao varchar(255), preco double precision, codigo varchar(40), icms double precision, ipi double precision );

CREATE GENERATOR GN_PRODUTOS;

SET TERM ^; CREATE TRIGGER INSPROD FOR PRODUTOS ACTIVE BEFORE INSERT AS BEGIN IF ((NEW.ID IS NULL) OR (NEW.ID = 0)) THEN NEW.ID = GEN_ID(GN_PRODUTOS,1); END ^ SET TERM ; ^

Criar Projeto no Delphi

65

Criar um MDIForm e o menu do sistema  Criar um DataModule para conexão no banco

Aqui é necessário colocar um componente de conexão ao banco e configurá-lo para acessar o banco com dados como o caminho do banco, usuário, senha e o driver de conexão ao banco. No create do DataModule adicionar o código para abrir a conexão com o banco de dados no inicio da execução do programa: dbxDB.Open;  Criar os cadastros (Visando a máxima produtividade, e considerando que a análise não considera questões de performance, foi utilizado DBNavigator conectado a um DataSet sem Where)

Cadastro de Clientes Inserir uma nova Form e defini-la como MDIChild Remover o código do dpr (para não criar o form na inicialização do programa):

Application.CreateForm(TfrmClientes, frmClientes); Incluir no evento onClose do form o código (para fechar o MDIChild): Action := caFree;

66

Incluir o DataModule na sessão Uses do form (neste caso a unit dm) : uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, dm;

Incluir os componentes de comunicação com o banco: Incluir um dataset, um provider,um ClientDataSet e um DataSource e fazer as ligações

No comandText do DataSet incluir o select : SELECT * FROM CLIENTES Incluir os campos na tela, incluir um DbNavigator. Para facilitar a consulta foi incluído um grid e um edit na mesma tela. No OnChange do edit a consulta foi implementada apenas no campo „nome‟.

Códigos utilizados: No FormCreate: cdsClientes.Open; // abre o ClientDataSet

67

No AfterPost do ClientDataSet e no AfterDelete do mesmo ClientDataSet: cdsClientes.ApplyUpdates(0); //aplica alterações no banco cdsClientes.Refresh; // atualiza o Client (porque o id é criado pelo trigger no banco)

No onChange do edit, para filtrar o grid cdsClientes.Filter := ' nome like ' + QuotedStr('%' + edNome.Text + '%');

Figura 9- Cadastro de Clientes em Delphi. A consulta é feita (apenas pelo campo „Nome‟) digitando no Edit acima do Grid.

Cadastro de Vendedores Inserir uma nova Form e defini-la como MDIChild

68

Remover o código do dpr (para não criar o form na inicialização do programa): Application.CreateForm(TfrmVendedores, frmVendedores); Incluir no evento onClose do form o código (para fechar o MDIChild): Action := caFree; Incluir o DataModule na sessão Uses do form (neste caso a unit dm) : uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, dm; Incluir os componentes de comunicação com o banco: Incluir um dataset, um provider,um ClientDataSet e um DataSource e fazer as ligações

No comandText do DataSet incluir o select : SELECT * FROM Vendedores

Incluir os campos na tela, incluir um DbNavigator. Para facilitar a consulta foi incluído um grid e um edit na mesma tela. No OnChange do edit a consulta foi implementada apenas no campo „nome‟.

69

Códigos utilizados: No FormCreate: cdsClientes.Open; // abre o ClientDataSet

No AfterPost do ClientDataSet e no AfterDelete do mesmo ClientDataSet: cdsClientes.ApplyUpdates(0); //aplica alterações no banco cdsClientes.Refresh; // atualiza o Client (porque o id é criado pelo trigger no banco)

No onChange do edit, para filtrar o grid cdsVendedores.Filter := ' nome like ' + QuotedStr('%' + edNome.Text + '%');

Figura 10 - Cadastro de Vendedores

70

Cadastro de Produtos Inserir uma nova Form e defini-la como MDIChild Remover o código do dpr (para não criar o form na inicialização do programa):

Application.CreateForm(TfrmProdutos, frmProdutos); Incluir no evento onClose do form o código (para fechar o MDIChild): Action := caFree;

Incluir o DataModule na sessão Uses do form (neste caso a unit dm) : uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, dm;

Incluir os componentes de comunicação com o banco: Incluir um dataset, um provider,um ClientDataSet e um DataSource e fazer as ligações No comandText do DataSet incluir o select : SELECT * FROM Produtos

71

Incluir os campos na tela, incluir um DbNavigator. Para facilitar a consulta foi incluído um grid e um edit na mesma tela. No OnChange do edit a consulta foi implementada apenas no campo „descricao‟.

Códigos utilizados: No FormCreate: cdsClientes.Open; // abre o ClientDataSet

No AfterPost do ClientDataSet e no AfterDelete do mesmo ClientDataSet: cdsClientes.ApplyUpdates(0); //aplica alterações no banco cdsClientes.Refresh; // atualiza o Client (porque o id é criado pelo trigger no banco) No onChange do edit, para filtrar o grid cdsProdutos.Filter := ' descricao like ' + QuotedStr('%' + edDesc.Text + '%');  Criar chamadas no menu para os cadastros Incluir no uses do MDIForm as units „clientes, vendedores, produtos‟: uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Menus ,clientes, vendedores, produtos;

72

Incluir no click de cada botão do menu criado o código para criar e abrir sua respectiva tela: TfrmClientes.Create(nil).Show; // no click do item de menu clientes TfrmVendedores.Create(nil).Show; //no click do item de menu vendedores TfrmProdutos.Create(nil).Show;//no click do item de menu produtos

Figura 11 - Cadastro de Produtos

73

4.2 Análise comparativa de criação de telas de cadastro Delphi X RubyOnRails

Requisitos

Delphi

Ruby on Rails

Instalação

Um instalador executa a instalação. A instalação de alguns componentes costuma ser simples (quando necessário).

Comandos shell são necessários. Alguns problemas de incompatibilidade de versões podem ocorrer e pode ser necessário recorrer a alguns fóruns de ajuda para sanar os problemas.

Configurações gerais de um projeto

Criar menus em um MDIForm, incluir um pequeno código no OnClose de todas as Child‟s (action:= caFree;) para poder fechar o form.

É necessário configurar arquivos e instalar e configurar plugins para cada aplicação.

Criação de cadastros

É necessário montar a tela visualmente O desenvolvimento e implementar um pouco de código. É necessário criar o banco de dados e gerenciar a comunicação com ele através dos componentes. acontece pela IDE e por comandos shell, o que pode ser um pouco confuso inicialmente. Porém o

74

desenvolvimento de telas muitas vezes se dá sem precisar montar a tela visualmente nem codificála. A conexão com o banco é feita automaticamente, pelo plugin ActiveScaffold. Utilizando esse plugin é possível se construir um cadastro em cerca de 3 minutos com todas as ações de um CRUD sem a necessidade de codificar essas ações.

75

5 IMPLEMENTAÇÃO DE VALIDAÇÕES

A implementação das validações é feita no Model do modelo MVC. O rails possui alguns métodos de validações já implementadas (para as mais usadas), entre elas: validates_presence_of(:nome , :message => "deve ser preenchido") #obriga o preenchimento do campo validates_uniqueness_of(:nome, :message => "já cadastrado") #bloqueia duplicação de registros validates_numericality_of(:idade, :greater_than => 0, :less_than => 100 , :message => "deve ser um numero entre 0 e 100") #validações numéricas validates_associated :cliente # valida integridade referencial Para usar esses métodos de validações, inclui-se no Model desejado o código. Continuando com os cadastros criados previamente, a seguir estão os passos para criar algumas validações em Rails:

Validações:  Obrigar o campo nome no cadastro de clientes

No Model “cliente.rb” (da pasta /app/models), adicione dentro da classe a linha: validates_presence_of(:nome , :message => "deve ser preenchido")

76

Impedir duplicação no campo RG no cadastro de clientes

No Model “cliente.rb” (da pasta /app/models), adicione dentro da classe a linha: validates_uniqueness_of(:rg, :message => "já cadastrado")

Validar o campo RG para receber apenas números

No Model “cliente.rb” (da pasta /app/models), adicione dentro da classe a linha: validates_numericality_of(:rg , :message => "deve ser apenas números")

Figura 12 - exemplo de mensagem de validação de campo

77

5.1 Análise comparativa com Delphi: Para obrigar o preenchimento de um campo e mostrar uma mensagem explicativa ao usuário, em Delphi, seria necessário algo como: Verificar a property isNull do field desejado do ClientDataSet antes de dar o post no ClientDataSet. Algo como: if cdsClientesNome.isNull then begin ShowMessage(„O campo Nome é obrigatório‟); exit; end;

Nesse caso é tão simples quanto no rails. Porém para verificar se o registro é único, como no exemplo de impedir cadastrar um cliente com um RG que já exista no sistema: No Rails a chamada validates_uniqueness_of(:rg, :message => "já cadastrado") dentro do model Cliente.rb resolveria. Mas no Delphi, por exemplo, como é inviável abrir todo a tabela no ClientDataSet (por questões de performance, quando se tem um cadastro com muitos registros), seria necessário criar uma função que verificasse com um select no banco de dados se existe um registro que já possui aquele RG. Além da funções nativas de validações, é possível criar funções para validações específicas, por exemplo:

78

validate :primeira_letra_maiuscula private def primeira_letra_maiuscula errors.add("nome","primeira letra deve ser maiúscula") unless nome =~ /[A-Z].*/ end }

Em ambiente web é muito comum o desenvolvedor precisar implementar mecanismos que cuidem para não perder os dados durante a validação do formulário (implementando a validação e Ajax, mantendo o conteúdo em session, etc). Porém no rails isso é feito sem a intervenção do programador. Tanto usando validações nativas, quanto implementando as validações, o gerenciamento para manter os dados que o usuário digitou no formulário é feito de forma transparente para o desenvolvedor. E todas as validações foram feitas sem a necessidade de escrever nenhuma linha de JavaScript.

79

6 SEGURANÇA EM RAILS

6.1 As principais formas de invasão na Web Na web existem diversas formas de invasão, mas destas 3 pontos são fundamentais de vulnerabilidade dos sistemas Web:

HTML Injection SQL Injection Cross site scripting

Html Injection consiste em cadastrar tags HTML ou Javascript em formulários , por exemplo, no cadastro de clientes o usuário pode informar no campo nome : "<script>alert("site inseguro")</script>". Em um sistema sem proteção contra HTML Injection, ao visualizar uma página que imprimiria o nome do usuário, seria executado o comando Java script (que pode ter diversos comportamentos indesejáveis)

SQL Injection é a habilidade de inserir SQL de modo a modificar os comandos de uma determinada view do sistema , por exemplo , em uma tela que executa a seguinte query: 'select senha , nome from usuarios where usuario = ' + edit1.value + ' '

80

Supondo que o usuário digite no edit1 o seguinte : a' or ' 1 = 1

Com isso ele consegue concatenar uma expressão no where da query (no caso a expressão „ or 1=1‟ ) e ele pode conseguir ver todos os usuários cadastrados no banco de dados. Cross site scripting é uma formas de invasão muito poderosa, que consiste em criar uma página pirata que consegue utilizar das sessões abertas para realizar uma invasão , por exemplo : Estatísticas dizem que 60 % dos usuários atuais da web trabalham logados no gmail e conseqüentemente no googledocs, baseado nisso um hacker cria uma página pirata com a seguinte action disparada por Java script : 'http://mail.google.com/mail/?method=_delete&cod_msg=1' , ou seja deleta o primeiro email do usuário. É muito comum desenvolvedores web não se preocuparem com esse tipo de situação. Talvez por costume, por não ser um padrão entre os desenvolvedores esse tipo de precaução ou talvez pelo trabalho de implementar proteções desse tipo.

6.2 As proteções nativas do rails O rails tem proteção nativa para as principais formas de ataque: Para proteger a aplicação de HTML injection basta introduzir a letra h , antes de imprimir um valor numa view, por exemplo : <%=h c.nome %>

81

Utilizando o ActiveScaffold para a criação de cadastros essa proteção já está implementada por padrão. Para proteger contra SQL injection, o rails tem o método find() com conditions que previne automaticamente grande parte dos métodos de SQL Injection. não utilizar o findbysql. O Ruby on Rails tem um filtro nativo de proteção contra SQL injection, o qual irá escapar ‟ , " , o caractere NULL e quebras de linhas. Utilizando o método find(id) ou findby_something(something) automaticamente aplica esta medida preventiva. Assim, evita-se usar o método findby_sql() que não possui essa proteção nativa. Utilizando esse método, é necessário implementar a proteção manualmente. A proteção contra ataque de cross-site, é ativa no rails por padrão. Não é necessário fazer nada.

6.3 Análise comparativa com PHP Em comparação com outras linguagens web, por exemplo o php, para evitar a SQL Injection seria necessário criar uma função para o tratamento das querys. O php possui a função mysql_real_escape_string(), que escapa os caracteres especiais como aspas simples e duplas antes de enviar para o banco de dados. Porém esta função não funciona em todas as versões do PHP, então é necessário verificar se ela existe, e caso não exista utiliza-se outra função, a mysql_escape_string().

82

Também é necessário se preocupar que se a diretiva get_magic_quotes_gpc() estiver ON ele irá acrescentar barras invertidas automaticamente antes de aspas simples e duplas, o problema é que ele irá enviar para o banco de dados com as barras invertidas, estragando o texto. Para contornar isso é necessário usar a função stripslashes() para remover essas barras invertidas. O código da função ficaria parecido com: <?php function anti_sql_injection($string) { $string = get_magic_quotes_gpc() ? stripslashes($string) : $string; $string = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($string) : mysql_escape_string($string); return $string; } ?> Enquanto que no rails já existe o método find(id) ou findby_something(something) que implementa essa segurança automaticamente.

Também em php, contra HTML injection, o desenvolvedor teria que implementar manualmente, tomando o devido cuidado para não causar outros problemas no sistema. Enquanto que em rails é necessário colocar o caractere „h‟ antes do campo. Por exemplo, <%=h c.nome %> . E utilizando alguns frameworks como o ActiveScaffold na criação dos cadastros essa proteção já funciona sem a intervenção do programador.

83

CONCLUSÃO
Assim como a maioria das ferramentas para desenvolvimento web, o rails tem complexidades para instalação (configuração de alguns arquivos, uma série de comandos shell, etc) e como a instalação é feita por partes (não existe um instalador único, são necessários comandos para o ruby, o rails, as gems, os plugins, etc) podem ocorrer alguns problemas durante a instalação. Ferramentas de desenvolvimento desktop não costumam ter esse tipo de complexidade (como o delphi). No inicio do projeto são necessários alguns ajustes de idioma e template de html e css, mas que pode ser contornado com a criação de um template padrão de projeto que seria herdado para a criação das aplicações, ou apenas com procedimentos bem definidos para evitar que alguma etapa seja esquecida e gere problemas futuros. O desenvolvimento do projeto é prático e facilitado por alguns frameworks como o ActiveScaffold, que gera todo um cadastro sem a necessidade do programador codificar o cadastro, desenhar as telas ou até mesmo criar o banco de dados (apenas quando desejável pode se customizar as telas de acordo com a necessidade). Algumas customizações como a validações de campos já são bem pré-implementadas com a criação de métodos que facilitam a implementação através de chamados simples a esses métodos. O rails já vem preparado contra os problemas mais comuns de segurança na web (que costuma ser ignorada por uma parte dos programadores web e trabalhosa para a outra parte que se preocupa com isso). Ele já possui alguns mecanismos de segurança embutidos e outros que são facilmente implementados. Seus plugins também implementam os métodos de segurança oferecidos pelo rails.

84

BIBLIOGRAFIA
EDUARDO: Por que Ruby on Rails? Disponível em:

<http://imasters.com.br/artigo/4746/programacao/porque_ruby_on_rails >. Acesso em:
14 Jul. 2010 FOWLER, Chad. Rails Recipes. Texaz, Pragmatic Bookshelf, 2007 Hansson: Ruby on Rails 2.1.x Tutorial. Disponível em: <http://www.tutorialspoint.com/ruby-on-rails-2.1/index.htm >. Acesso em: 14 Jul. 2010 STEWART: An Interview with the creator of Ruby. Disponível em: <http://linuxdevcenter.com/pub/a/linux/2001/11/29/ruby.html >. Acesso em: 14 Jul. 2010 THOMAS, Dave; HANSSON, David Heinemeier. Agile Web Development with Rails. 3ª ed. Pragmatic Bookshelf, 2009 URUBATAN, Rodrigo. Ruby on Rails Desenvolvimento fácil e rápido de aplicações web. Novatec, 2009 YEHUDA: Metaprogramming in Ruby. Disponível em:

<http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/ >.
Acesso em: 14 Jul. 2010

FATEC – SP Faculdade de Tecnologia de São Paulo

Desenvolvimento ágil com Ruby on Rails

São Paulo, SP 2010

Sign up to vote on this title
UsefulNot useful