Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas

Aprendeda Desenvolvimento com Ruby e Rails, Notas de estudo de Cultura

aprenda desenvolvimento agil na web com o ruby

Tipologia: Notas de estudo

2010
Em oferta
30 Pontos
Discount

Oferta por tempo limitado


Compartilhado em 02/07/2010

victor-fernandes-14
victor-fernandes-14 🇧🇷

5

(1)

1 documento

1 / 165

Discount

Em oferta

Documentos relacionados


Pré-visualização parcial do texto

Baixe Aprendeda Desenvolvimento com Ruby e Rails e outras Notas de estudo em PDF para Cultura, somente na Docsity! RR-71 Desenvolvimento Ágil para Web 2.0 com Ruby on Rails A Caelum atua no mercado com consultoria, desenvolvimento e ensino em computação. Sua equipe participou do desenvolvimento de projetos em vários clientes e, após apresentar os cursos de verão de Java na Universidade de São Paulo, passou a oferecer treinamentos para o mercado. Toda a equipe tem uma forte presença na comunidade através de eventos, artigos em diversas revistas, participação em muitos projetos open source como o VRaptor e o Stella e atuação nos fóruns e listas de discussão como o GUJ. Com uma equipe de mais de 60 profissionais altamente qualificados e de destaque do mercado, oferece treinamentos em Java, Ruby on Rails e Scrum em suas três unidades - São Paulo, Rio de Janeiro e Brasília. Mais de 8 mil alunos já buscaram qualificação nos treinamentos da Caelum tanto em nas unidades como nas próprias empresas com os cursos incompany. O compromisso da Caelum é oferecer um treinamento de qualidade, com material constantemente atualizado, uma metodologia de ensino cuidadosamente desenvolvida e instrutores capacitados tecnicamente e didaticamente. E oferecer ainda serviços de consultoria ágil, mentoring e desenvolvimento de projetos sob medida para empresas. Comunidade Nossa equipe escreve constantemente artigos no Blog da Caelum que já conta com 150 artigos sobre vários assuntos de Java, Rails e computação em geral. Visite-nos e assine nosso RSS: ➡ blog.caelum.com.br Acompanhe também a equipe Caelum no Twitter: ➡ twitter.com/caelumdev/equipe O GUJ é maior fórum de Java em língua portuguesa, com 700 mil posts e 70 mil usuários. As pessoas da Caelum participam ativamente, participe também: ➡ www.guj.com.br Assine também nossa Newsletter para receber as novidades e destaques dos eventos, artigos e promoções da Caelum: ➡ www.caelum.com.br/newsletter No site da Caelum há algumas de nossas Apostilas disponíveis gratuitamente para download e alguns dos artigos de destaque que escrevemos: ➡ www.caelum.com.br/apostilas ➡ www.caelum.com.br/artigos Índice 1 Agilidade na Web 1 1.1 A agilidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 A comunidade Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.3 Bibliografia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.4 Tirando dúvidas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.5 Para onde ir depois? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2 A linguagem Ruby 4 2.1 A história do Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.2 Características . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.3 Instalação do interpretador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.4 Outras implementações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 2.5 MagLev . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.6 Ruby Enterprise Edition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.7 Interactive Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.8 Tipos Básicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.9 Para Saber Mais - Desafios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.10 Para Saber Mais - Desafio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 3 Ruby Avançado 13 3.1 Mundo orientado a objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.2 Métodos comuns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 3.3 Meta-programação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 i 3.4 Definição de métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 3.5 Discussão: Enviando mensagens aos objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 3.6 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 3.7 Desafio: Classes abertas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.8 self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.9 Desafio: self e o método puts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.10 Atributos e propriedades: acessores e modificadores . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.11 Syntax Sugar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3.12 Métodos de Classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.13 Para saber mais: Singleton Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.14 Metaprogramação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3.15 Convenções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.16 Coleções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.17 Blocos e Programação Funcional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.18 Desafio: Usando blocos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.19 Mais OO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.20 Modulos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.21 Manipulando erros e exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.22 Exercício: Manipulando exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.23 Arquivos Ruby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 4 Ruby on Rails 31 4.1 Ruby On Rails - Apresentação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 4.2 Aprender Ruby? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 4.3 RadRails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 4.4 Primeira Aplicação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 4.5 Exercícios: Iniciando o Projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 4.6 Estrutura dos diretórios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 4.7 O Banco de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 4.8 Exercícios: Criando o banco de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 4.9 A base da construção: scaffold (andaime) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 4.10 Exercícios: Scaffold . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 ii 4.11 Gerar as tabelas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.12 Versão do Banco de Dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 4.13 Exercícios: Migrar tabela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 4.14 Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 4.15 Documentação do Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 4.16 Exercício Opcional: Utilizando a documentação . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 5 Active Record 47 5.1 Motivação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 5.2 Exercícios: Controle de Restaurantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 5.3 Modelo - O “M” do MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 5.4 ActiveRecord . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 5.5 Rake . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 5.6 Criando Modelos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.7 Migrations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 5.8 Exercícios: Criando os modelos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 5.9 Manipulando nossos modelos pelo console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 5.10 Exercícios: Manipulando registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 5.11 Exercícios Opcionais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 5.12 Finders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 5.13 Exercícios: Buscas dinâmicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 5.14 Validações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 5.15 Exercícios: Validações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 5.16 Exercícios - Completando nosso modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 5.17 O Modelo Qualificação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 5.18 Exercícios - Criando o Modelo de Qualificação . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 5.19 Relacionamentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 5.20 Para Saber Mais: Auto-relacionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 5.21 Para Saber Mais: Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 5.22 Exercícios - Relacionamentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 5.23 Para Saber Mais - Eager Loading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 5.24 Para Saber Mais - Named Scopes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 5.25 Para Saber Mais - Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 iii 14 Apêndice B - Integrando Java e Ruby 144 14.1 O Projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 14.2 Testando o JRuby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 14.3 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 14.4 Testando o JRuby com Swing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 15 Apêndice C - Deployment 146 15.1 Webrick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 15.2 CGI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 15.3 FCGI - FastCGI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 15.4 Lighttpd e Litespeed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 15.5 Mongrel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 15.6 Proxies Reversos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 15.7 Phusion Passenger (mod_rails) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 15.8 Ruby Enterprise Edition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 15.9 Exercícios: Deploy com Apache e Passenger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 16 Apêndice D - Instalação 152 16.1 Ruby - Ubuntu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 16.2 Ruby - Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 16.3 Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 16.4 JDK . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 16.5 Aptana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 16.6 Mongrel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 16.7 MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 16.8 SVN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 Versão: 12.3.27 vi CAPÍTULO 1 Agilidade na Web “Não são os milagres que inclinam o realista para a fé. O verdadeiro realista, caso não creia, sempre encontrará em si força e capacidade para não acreditar no milagre, e se o milagre se apresenta diante dele como fato irrefutável, é mais fácil ele descrer de seus sentidos que admitir o fato” – Fiodór Dostoievski, em Irmãos Karamazov 1.1 - A agilidade Quais são os problemas mais frequentes no desenvolvimento web? Seriam os problemas com AJAX? Escrever SQL? Tempo demais para gerar os CRUDs básicos? Com tudo isso em mente, David Heinemeier Hansson, trabalhando na 37Signals, começou a procurar uma linguagem de programação que pudesse utilizar para desenvolver os projetos de sua empresa. Mais ainda, criou um framework web para essa linguagem, que permitiria a ele escrever uma aplicação web de maneira simples e elegante. O que possibilita toda essa simplicidade são os recursos poderosos que Ruby oferece e que deram toda a simplicidade ao Rails. Esses recursos proporcionados pela linguagem Ruby são fundamentais de serem compreendidos por todos que desejam se tornar bons desenvolvedores Rails e por isso o começo desse curso foca bastante em apresentar as características da linguagem e seus diferenciais. Um exemplo clássico da importância de conhecer mais a fundo a linguagem Ruby está em desvendar a “magia negra” por trás do Rails. Conceitos como meta programação, onde código é criado dinâmicamente, são essenciais para o entendimento de qualquer sistema desenvolvido em Rails. É a meta programação que permite, por exemplo, que tenhamos classes extremamente enxutas e que garante o relacionamento entre as tabelas do banco de dados com nossas classes de modelo sem a necessidade de nenhuma linha de código, apenas usando de convenções. Esse curso apresenta ainda os conceitos de programação funcional, uso de blocos, duck typing, enfim, tudo o que é necessário para a formação da base de conceitos que serão utilizados ao longo do curso e da vida como um desenvolvedor Rails. 1.2 - A comunidade Rails A comunidade Rails é hoje uma das mais ativas e unidas do Brasil. Cerca de 10 eventos acontecem anu- almente com o único propósito de difundir conhecimento e unir os desenvolvedores. Um exemplo dessa força é o Rails Summit, maior evento de Rails da America Latina, com presença dos maiores nomes nacionais e internacionais de Ruby on Rails. Além dos eventos, diversos blogs sobre Rails tem ajudado diversos programadores a desvendar esse novo universo: • http://blog.caelum.com.br/ - Blog da Caelum 1 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails • http://andersonleite.com.br/ - Anderson Leite • http://guilhermesilveira.wordpress.com/ - Guilherme Silveira • http://yehudakatz.com/ - Yehuda Katz • http://caueguerra.com - Cauê Guerra • http://fabiokung.com/ - Fabio Kung • http://akitaonrails.com/ - Fábio Akita • http://blog.plataformatec.com.br/ - José Valim • http://www.nomedojogo.com/ - Carlos Brando • http://railsenvy.com/ - Rails Envy • http://www.rubyinside.com.br/ - RubyInside Brasil • http://rubyflow.com/ - Rubyflow A Caelum aposta no Rails desde 2007, quando criamos o primeiro curso a respeito. E o ano de 2009 marcou o Ruby on Rails no Brasil, ano em que ele foi adotado por diversas empresas grandes e até mesmo orgãos do governo, como mencionado num post em nosso blog no começo do mesmo ano: http://blog.caelum.com.br/2009/01/19/2009-ano-do-ruby-on-rails-no-brasil/ 1.3 - Bibliografia • Agile Web Development with Rails - Sam Ruby, Dave Thomas, David Heinemeier Hansson Esse é o livro referência no aprendizado de Ruby on Rails, criado pelo autor do framework. Aqui, ele mostra através de um projeto, os principais conceitos e passos no desenvolvimento de uma aplicação completa. • Programming Ruby: The Pragmatic Programmers’ Guide - Dave Thomas, Chad Fowler, Andy Hunt Conhecido como “Pickaxe”, esse livro pode ser considerado a bíblia do programador Ruby. Cobre toda a especificação da linguagem e procura desvendar toda a “magia” do Ruby. • The Pragmatic Programmer: From Journeyman to Master - Andrew Hunt, David Thomas As melhores práticas para ser um bom desenvolvedor: desde o uso de versionamento, ao bom uso do logging, debug, nomenclaturas, como consertar bugs, etc. Existe ainda um post no blog da Caelum sobre livros que todo desenvolvedor Rails deve ler: http://blog. caelum.com.br/2009/08/25/a-trinca-de-ases-do-programador-rails/ Capítulo 1 - Agilidade na Web - Bibliografia - Página 2 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails (conhecidas no mundo de Ruby como gems) uma vez que essa é uma versão de transição até o Ruby 2.0 onde serão inclusas diversas mudanças e novas funcionalidades. A maioria das distribuições Linux possuem o pacote de uma das última versões estáveis (em geral, 1.8.7) pronto para ser instalado. O exemplo mais comum de instalação é para o Ubuntu: sudo apt-get install ruby1.8 ruby1.8-dev O interpretador ruby (MRI) já vem instalado no Mac OS X. Apesar de existirem soluções prontas para a instalação do Ruby em diversas plataformas (one-click- installers), sempre é possível baixá-lo pelo site oficial: http://ruby-lang.org Após a instalação, não deixe de conferir se o interpretador está disponível na sua variável de ambiente PATH: $ ruby --version ruby 1.8.6 (2007-09-24 patchlevel 111) [i486-linux] A saída pode ser um pouco diferente, dependendo do sistema operacional e da versão instalada. Nesta apostila existe um apêndice sobre a instalação e detalhes do Ruby, caso você esteja enfrentando problemas. Ruby possui um gerenciador de pacotes e dependências bastante avançado, flexível e eficiente: Ruby- Gems. Os gems são bibliotecas reutilizáveis de código Ruby, que podem até conter algum código nativo (em C, Java, .Net). São análogos aos jars do mundo Java, ou os assemblies do mundo .Net. RubyGems é um sistema gerenciador de pacotes comparável a qualquer um do mundo *NIX, como o apt-get, o MacPorts (BSD Ports), o yum, entre outros. Portanto, para sermos capazes de instalar e utilizar as centenas de gems disponíveis, precisamos instalar além do interpretador Ruby, o Rubygems. Basta baixá-lo através da urlo abaixo e executar o script de instalação contido no pacote: http://www.rubygems.org/ cd rubygems-1.x.x ruby setup.rb Capítulo 2 - A linguagem Ruby - Instalação do interpretador - Página 5 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 2.4 - Outras implementações Com a popularização da linguagem Ruby (iniciada pelo Ruby on Rails), implementações alternativas da linguagem começaram a ficar em evidência. A maioria delas segue uma tendência natural de serem baseados em uma Máquina Virtual ao invés de serem simples interpretadores. Algumas implementações possuem até compiladores completos, que transformam o código Ruby em alguma linguagem intermediária a ser interpretada por uma máquina virtual. O próprio Ruby 1.9 de referência (YARV), evolução do MRI, é baseado em uma máquina virtual: Yet Another Ruby VM. A principal vantagem das máquinas virtuais é facilitar o suporte em diferentes plataformas. Além disso, ter código intermediário permite otimização do código em tempo de execução, feito através da JIT. JRuby foi a primeira implementação completa da versão 1.8.6 do Ruby. O JRuby é a principal implemen- tação em Java da linguagem Ruby e é hoje considerada por muitos como a implementação mais rápida da linguagem. Não é um simples interpretador, já que também opera nos modos AOT - compilação Ahead Of Time e JIT - Just In Time compilation, além do modo interpretador tradicional (Tree Walker ). Teremos um capítulo exclusivo sobre JRuby, mas uma de suas principais vantagens é a interoperabilidade com código Java existente, além de aproveitar todas as vantagens de uma das plataformas de execução de código mais maduras (GC, JIT, Threads nativas, entre outras). Além disso, a própria Sun Microsystems aposta no projeto, já que alguns de seus principais desenvolve- dores, Charles Nutter (líder técnico do projeto), Tomas Enebo e Nick Sieger já trabalharam para ela. Ola Bini também é contratado pela ThoughtWorks para trabalhar apenas com JRuby. A comunidade .Net também não ignora o sucesso da linguagem e patrocina o projeto IronRuby, mantido pela própria Microsoft. IronRuby foi um dos primeiros projetos verdadeiramente de código aberto dentro da Microsoft. Ruby.NET é outro projeto que tem como objetivo possibilitar código Ruby ser executado na plataforma .Net. Originalmente conhecido como Gardens Point Ruby.NET Compiler, procura ser um compilador de código Ruby para a CLR do mundo .Net. Criada por Evan Phoenix, Rubinius é um dos projetos que tem recebido mais atenção pela comunidade Ruby, por ter o objetivo de criar a implementação de Ruby com a maior parte possível do código em Ruby. Além disso, trouxe idéias de máquinas virtuais do SmallTalk, possuindo um conjunto de instruções (bytecode) próprio e implementada em C/C++. http://rubini.us O projeto Rubinius possui uma quantidade de testes enorme, escritos em Ruby. O que incentivou a iniciativa de especificar a linguagem Ruby. O projeto RubySpec (http://rubyspec.org/) é um acordo entre os vários im- plementadores da linguagem Ruby para especificar as características da linguagem Ruby e seu comportamento, através de código executável, que funciona como um TCK (Test Compatibility Kit). RubySpec tem origem na suíte de testes unitários do projeto Rubinius, escritos com uma versão mínima do RSpec, conhecida como MSpec. O RSpec é um framework para descrição de especificações no estilo pregado pelo Behavior Driven Development. Veremos mais sobre isso no capítulo de testes. Capítulo 2 - A linguagem Ruby - Outras implementações - Página 6 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 2.5 - MagLev Avi Bryant é um programador Ruby conhecido, que mudou para Smalltalk e hoje é um defensor fervoroso da linguagem; além de ser um dos criadores do principal framework web em SmallTalk: Seaside. Durante seu keynote na RailsConf de 2007, lançou um desafio à comunidade: “I’m from the future, I know how this story ends. All the people who are saying you can’t implement Ruby on a fast virtual machine are wrong. That machine already exists today, it’s called Gemstone, and it could certainly be adapted to Ruby. It runs Smalltalk, and Ruby essentially is Smalltalk. So adapting it to run Ruby is absolutely within the realm of the possible.” Ruby e Smalltalk são parecidos demais. Avi basicamente pergunta: por que não criar máquinas virtuais para Ruby, aproveitando toda a tecnologia de máquinas virtuais para SmallTalk, que já têm bastante maturidade e estão no mercado a tantos anos? Integrantes da empresa Gemstone, que possui uma das máquinas virtuais para SmallTalk mais famosas - Gemstone/S, estavam na platéia e chamaram o Avi Bryant para provar que isto era possível. Na RailsConf de 2008, o resultado foi que a Gemstone apresentou o produto que estão desenvolvendo, conhecido como Maglev. É uma máquina virtual para Ruby, baseada na existente para Smalltalk. As linguagens são tão parecidas que apenas poucas instruções novas tiveram de ser inseridas na nova máquina virtual. Os números apresentados são surpreendentes. Com tão pouco tempo de desenvolvimento, conseguiram apresentar um ganho de até 30x de performance em alguns micro benchmarks. Apesar de ter feito bastante barulho durante a RailsConf 2008, a Gemstone anda bastante quieta sobre o Maglev e não mostrou mais nada desde então. Muitos criticam esta postura da empresa de ter falado sobre algo tão antes de poderem mostrar, além de terem exibido números que não podem provar. Antonio Cangiano teve acesso a uma versão preliminar do Maglev e publicou um famoso comparativo de performance (benchmark ) em seu blog, conhecido como “The Great Ruby Shootout”, em que o Maglev se mostra em média 1.8x mais rápido que a MRI. Sendo muito mais rápido em alguns benchmarks e muito mais lento em alguns outros. http://antoniocangiano.com/2008/12/09/the-great-ruby-shootout-december-2008/ 2.6 - Ruby Enterprise Edition Para melhorar a performance de aplicações Rails e diminuir a quantidade de memória utilizada, Ninh Bui, Hongli Lai e Tinco Andringa (da Phusion) modificaram o interpretador Ruby e lançaram com o nome de Ruby Enterprise Edition. As principais modificações no REE foram no comportamento do Garbage Collector, fazendo com que fun- cione com o recurso de Copy on Write disponível na maioria dos sistemas operacionais baseados em UNIX (Linux, Solaris, ...). Outra importante modificação foi na alocação de memória do interpretador, com o uso de bibliotecas famo- sas como tcmalloc. Os desenvolvedores da Phusion já ofereceram as modificações (patches) para entrar na implementação oficial, MRI. É ainda um mistério para a comunidade o porquê de tais modificações importantes ainda não terem entrado para a versão oficial do interpretador. http://izumi.plan99.net/blog/index.php/2008/08/17/ _ making-ruby’s-garbage-collector-copy-on-write- friendly-part-8/ Capítulo 2 - A linguagem Ruby - MagLev - Página 7 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Symbol Símbolos também são texto, como as Strings. Só que devem ser precedidos do caracter ’:’, ao invés de aspas e pertencem à classe Symbol: >> puts :simbolo simbolo => nil >> :simbolo.class => Symbol As principais diferenças são: • São imutáveis. Uma vez criado, um símbolo não pode ser alterado. Se precisarmos de um novo valor, precisa criar um novo objeto símbolo. • São compartilhados. Ruby compartilha o mesmo objeto na memória em todos os lugares da aplicação que usarem um símbolo de mesmo valor. Todos os lugares da aplicação que contém o código :coracao, estão se referindo ao mesmo objeto na memória. Por causa destas características, símbolos são análogos às Strings do Java. As Strings do Ruby estão mais para o StringBuilder do Java. Por serem imutáveis e compartilhados, objetos Symbol geralmente são usados como identificadores ou para nomenclatura (labels). 2.10 - Para Saber Mais - Desafio 1) Por que a comparação entre símbolos é muito mais rápida que entre Strings? s1 = :abc s2 = :abc s1 == s2 # => true t1 = "abc" t2 = "abc" t1 == t2 # => true Boolean Há também os objetos do tipo booleano, true e false. Os operadores booleanos aceitam quaisquer expres- sões aritméticas: >> 3 > 2 => true >> 3+4-2 <= 3*2/4 => false Os operadores booleanos são: ==, >, <, >= e <=. Expressões booleanas podem ainda ser combinadas com os operadores && (and) e || (or). Capítulo 2 - A linguagem Ruby - Para Saber Mais - Desafio - Página 10 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Ruby fornece uma maneira de trabalharmos com sequências de uma forma bem simples: (1..3) # range representando números de 1 ‘a 3. (‘a’..’z’) # range representando letras minúsculas do alfabeto (0...5) # range representando números de 1 ‘a 4. Palavras Reservadas alias and BEGIN begin break case class def defined do else elsif END end ensure false for if in module next nil not or redo rescue retry return self super then true undef unless until when while yield O if do ruby aceita qualquer expressão booleana, no entanto, cada objeto em Ruby possui um “valor booleano”. Os únicos objetos de valor booleano false são o próprio false e o nil. Portanto, qualquer valor pode ser usado como argumento do if: >> abc = nil => nil >> if(abc) >> puts("nao imprime") >> end => nil >> if(3 == 3) >> puts("agora imprime") >> end agora imprime => nil Teste também o switch: def proucura_sede_copa_do_mundo( ano ) case ano when 1895..1993 "Não lembro... :)" when 1994 "Estados Unidos" when 1998 "França" end end puts proucura_sede_copa_do_mundo(1994) O código acima funciona como uma série de if/elsif : if 1994 == ano "Estados Unidos" elsif 1998 == ano "França" elsif 1895..1993 == ano "Não lembro... :)" end Ruby possui bom suporte a expressões regulares, fortemente influenciado pelo Perl. Expressões regulares literais são delimitadas por / (barra). Capítulo 2 - A linguagem Ruby - Para Saber Mais - Desafio - Página 11 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails >> /.*lalalala/ =~ "asdasdasdas" => nil >> /sd.*/ =~ "asdasdasd" => 1 O operador =~ faz a função de match e retorna a posição da String onde o padrão foi encontrado, ou nil caso a String não bata com a expressão regular. MatchData Há também o método match, que retorna um objeto do tipo MatchData, ao invés da posição do match. O objeto retornado pelo método match contém diversas informações úteis sobre o resultado da expressão regular, como o valor de agrupamentos (captures) e posições (offset) em que a expressão regular bateu. Podemos lidar com requisições HTTP utilizando o código abaixo. require ’net/http’ Net::HTTP.start( ’www.caelum.com.br’, 80 ) do |http| print( http.get( ’/’ ).body ) end Para manipular arquivos de texto existe a classe File: print "Escreva um texto: " texto = gets File::open( "caelum.txt", "w" ) do |f| f << texto end Dir[’caelum.txt’].each do |file_name| idea = File.read( file_name ) puts idea end O operador ||= atribui o valor caso a variável esteja vazia, ou mantém caso ela exista. dez = 8 n = dez ||= 10 puts n Capítulo 2 - A linguagem Ruby - Para Saber Mais - Desafio - Página 12 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails def pessoa.vai(lugar) "indo para #{lugar}" end Para receber vários argumentos em um método, basta separá-los por vírgula: def pessoa.troca(roupa, lugar) "trocando de #{roupa} no #{lugar}" end A invocação desses métodos é feita da maneira tradicional: pessoa.troca(’camiseta’, ’banheiro’) Alguns podem até ter um valor padrão, fazendo com que sejam opcionais: def pessoa.troca(roupa, lugar=’banheiro’) "trocando de #{roupa} no #{lugar}" end # invocacao sem o parametro: pessoa.troca("camiseta") # invocacao com o parametro: pessoa.troca("camiseta", "sala") 3.5 - Discussão: Enviando mensagens aos objetos 1) Na orientação a objetos a chamada de um método é análoga ao envio de uma mensagem ao objeto. Cada objeto pode reagir de uma forma diferente à mesma mensagem, ao mesmo estímulo. Isso é o polimorfismo. Seguindo a idéia de envio de mensagens, uma maneira alternativa de chamar um método é usar o método send(), que todo objeto em Ruby possui. pessoa.send(:fala) O método send recebe como argumento o nome do método a ser invocado, que pode ser um símbolo ou uma string. De acordo com a orientação a objetos é como se estivéssemos enviando a mensagem “fala” ao objeto pessoa. Além da motivação teórica, você consegue enxergar um outro grande benefício dessa forma de invocar métodos, através do send()? Qual? 3.6 - Classes Para não precisar adicionar sempre todos os métodos em todo objeto que criamos, Ruby possui classes, que atuam como fábricas (molde) de objetos. Classes possibilitam a criação de objetos já incluindo alguns métodos. class Pessoa def fala puts "Sei Falar" end Capítulo 3 - Ruby Avançado - Discussão: Enviando mensagens aos objetos - Página 15 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails def troca(roupa, lugar="banheiro") "trocando de #{roupa} no #{lugar}" end end p = Pessoa.new # o objeto apontado por p já nasce com os métodos fala e troca. Todo objeto em Ruby possui o método class, que retorna a classe que originou este objeto (note que os parênteses podem ser omitidos na chamada e declaração de métodos): p.class # => Pessoa O diferencial de classes em Ruby é que são abertas. Ou seja, qualquer classe pode ser alterada a qualquer momento na aplicação. Basta reabrir a classe e fazer as mudanças: class Pessoa def novo_metodo # ... end end Caso a classe Pessoa já exista estamos apenas reabrindo sua definição para adicionar mais código. Não será criada uma nova classe e nem haverá um erro dizendo que a classe já existe. 3.7 - Desafio: Classes abertas 1) Qualquer classe em Ruby pode ser reaberta e qualquer método redefinido. Inclusive classes e métodos da biblioteca padrão, como Object e Fixnum. Podemos redefinir a soma de números reabrindo a classe Fixnum? Isto é útil? class Fixnum def +(outro) self - outro # fazendo a soma subtrair end end 3.8 - self Um método pode chamar outro método do próprio objeto. Para isto, basta usar a referência especial self, que aponta para o para o próprio objeto. É análogo ao this de outras linguagens como Java e C#. Todo método em Ruby é chamado em algum objeto, ou seja, um método é sempre uma mensagem enviada a um objeto. Quando não especificado, o destino da mensagem é sempre self: class Conta def transfere_para(destino, quantia) debita quantia # mesmo que self.debita(quantia) Capítulo 3 - Ruby Avançado - Desafio: Classes abertas - Página 16 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails destino.deposita quantia end end 3.9 - Desafio: self e o método puts 1) Vimos que todo método é sempre chamado em um objeto. Quando não especificamos o objeto em que o método está sendo chamado, Ruby sempre assume que seja em self. Como tudo em Ruby é um objeto, todas as operações devem ser métodos. Em especial, puts não é uma operação, muito menos uma palavra reservada da linguagem. puts "ola!" Em qual objeto é chamado o método puts? Por que podemos chamar puts em qualquer lugar do programa? (dentro de classes, dentro de métodos, fora de tudo, ...) 2) Se podemos chamar puts em qualquer self, por que o código abaixo não funciona? (Teste!) obj = "uma string" obj.puts "todos os objetos possuem o método puts?" 3) (opcional) Pesquise onde (em que classe ou algo parecido) está definido o método puts. Uma boa dica é usar a documentação oficial da biblioteca padrão: http://ruby-doc.org 3.10 - Atributos e propriedades: acessores e modificadores Atributos, também conhecidos como variáveis de instância, em Ruby são sempre privados e começam com @. Não há como alterá-los de fora da classe; apenas os métodos de um objeto podem alterar os seus atributos (encapsulamento!). class Pessoa def muda_nome(novo_nome) @nome = novo_nome end def diz_nome "meu nome é #{@nome}" end end p = Pessoa.new p.muda_nome "João" p.diz_nome # => "João" Podemos fazer com que algum código seja executado na criação de um objeto. Para isso, todo objeto pode ter um método especial, chamado de initialize: Capítulo 3 - Ruby Avançado - Desafio: self e o método puts - Página 17 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails # ... end 3.13 - Para saber mais: Singleton Classes A definição class << object define as chamadas singleton classes em ruby. Por exemplo, uma classe normal em ruby poderia ser: class Pessoa def fala puts ’oi’ end end Podemos instancia e invocar o método normalmente: p = Pessoa.new p.fala # imprime ’oi’ Entretanto, também é possível definir métodos apenas para esse objeto “p”, pois tudo em ruby, até mesmo as classes, são objetos, fazendo : class Pessoa def p.anda puts ’andando’ end end O método “anda” é chamado de singleton method do objeto “p”. E onde estão os singleton methods ? Um singleton method “vive” em uma singleton class. Todo objeto em ruby possui 2 classes: • a classe a qual foi instanciado • sua singleton class A singleton class é exclusiva para guardar os metodos desse objeto, sem compartilhar com outras instâncias da mesma classe. E como defino uma singleton class ? Existe uma notação especial para definir uma singleton class: class << Pessoa def anda puts ’andando’ end end Capítulo 3 - Ruby Avançado - Para saber mais: Singleton Classes - Página 20 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Definindo o código dessa forma temos o mesmo que no exemplo anterior, porém definindo o método anda explicitamente na singleton class.É possível ainda definir tudo na mesma classe: class Pessoa class << self def anda puts ’andando’ end end end Mais uma vez o método foi definido apenas para um obejto, no caso , o objeto “Pessoa”, podendo ser executado com: Pessoa.anda 3.14 - Metaprogramação Levando o dinamismo de Ruby ao extremo, podemos criar métodos que definem métodos em outros objetos: class Aluno # nao sabe nada end class Professor def ensina(aluno) def aluno.escreve "sei escrever!" end end end juca = Aluno.new juca.respond_to? :escreve # => false professor = Professor.new professor.ensina juca juca.escreve # => "sei escrever!" A criação de métodos acessores é uma tarefa muito comum no desenvolvimento orientado a objetos. Os métodos são sempre muito parecidos e os desenvolvedores costumam usar recursos de geração de códigos das IDEs para automatizar esta tarefa. Já vimos que podemos criar código Ruby que escreve código Ruby (métodos). Aproveitando essa possi- bilidade do Ruby, existem alguns métodos de classe importantes que servem apenas para criar alguns outros métodos nos seus objetos. class Pessoa attr_accessor :nome end Capítulo 3 - Ruby Avançado - Metaprogramação - Página 21 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails p = Pessoa.new p.nome = "Joaquim" puts p.nome # => "Joaquim" A chamada do método de classe attr_acessor, define os métodos nome e nome= na classe Pessoa. A técnica de código gerando código é conhecida como metaprogramação, ou metaprogramming. Visibilidade dos métodos Outro exemplo interessante de metaprogramação é como definimos a visibilidade dos métodos em Ruby. Por padrão, todos os métodos definidos em uma classe são públicos, ou seja, podem ser chamados por qualquer um. Não existe nenhuma palavra reservada (keyword) da linguagem para mudar a visibilidade. Isto é feito com um método de classe. Toda classe possui os métodos private, public e protected, que são métodos que alteram outros métodos, mudando a sua visibilidade (código alterando código == metaprogramação). Como visto, por padrão todos os métodos são públicos. O método de classe private altera a visibilidade de todos os métodos definidos após ter sido chamado: class Pessoa private def vai_ao_banheiro # ... end end Todos os métodos após a chamada de private são privados. Isso pode lembrar um pouco C++, que define regiões de visibilidade dentro de uma classe (seção pública, privada, ...). Um método privado em Ruby só pode ser chamado em self e o self deve ser implícito. Em outras palavras, não podemos colocar o self explicitamente para métodos privados, como em self.vai_ao_banheiro. Caso seja necessário, o método public faz com que os métodos em seguida voltem a ser públicos: class Pessoa private def vai_ao_banheiro # ... end public def sou_um_metodo_publico # ... end end Capítulo 3 - Ruby Avançado - Metaprogramação - Página 22 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails meu_metodo do puts "este" puts :bloco puts "tem" puts :varias puts "linhas" end O método que recebe o bloco pode decidir se deve ou não chamá-lo. Para chamar o bloco associado, usamos a palavra reservada yield. def meu_metodo puts "chamando o bloco associado" yield end meu_metodo { puts "bloco chamado" } # => chamando o bloco associado # => bloco chamado Blocos podem receber parâmetros: def passa_parametro yield("algum", "texto") # parenteses opcionais end passa_parametro { |m1, m2| puts "#{m1}, #{m2}" } # ou passa_parametro do |m1, m2| puts "m1: #{m1}" puts "m2: #{m2}" end Entender quando usar blocos é complicado no início. Você pode enxergá-los como uma oportunidade do método delegar parte da responsabilidade a quem o chama. A biblioteca padrão do Ruby faz alguns usos muito interessantes de blocos. Podemos analizar a forma de iterar em coleções, que é bastante influenciada por técnicas de programação funcional. Blocos trazem uma característica funcional à linguagem Ruby. Dizer que estamos passando uma função (pedaço de código) como parâmetro a outra função é o mesmo que passar blocos na chamada de métodos. Todo Array possui o método each, que chama o bloco de código associado para cada um dos seus items, passando o item como parâmetro ao bloco: lista = ["4", "um", "cinco", "bla"] lista.each do |item| puts item end A construção acima não parece trazer muitos ganhos se comparada a forma tradicional e imperativa de iterar em um array (for). Podemos continuar com a idéia analisando o método map (ou collect), que coleta os retornos de todas as chamadas do bloco associado: Capítulo 3 - Ruby Avançado - Blocos e Programação Funcional - Página 25 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails lista = ["quatro", "um", "cinco", "bla"] novo = lista.map do |item| item.upcase end novo # => ["QUATRO", "UM", "CINCO", "BLA"] Na programação imperativa tradicional precisaríamos de no mínimo mais duas linhas, para o array auxiliar e para ir adicionando os items maiúsculos no novo array. Os outros métodos do módulo Enumerable seguem a mesma idéia: find, find_all, grep, sort, inject. Não deixe de consultar a documentação! [Para saber mais: Mais sobre blocos] Analise e rode o código abaixo, olhe na documentação o método sort_by e teste o next. caelum = [ {:ruby => ’rr-71’, :java => ’fj-11’}, {:ruby => ’rr-75’, :java => ’fj-21’} ] caelum.sort_by { |curso| curso[:ruby] }.each do |curso| puts "Curso de RoR na Caelum: #{ curso[:ruby] }" end caelum.sort_by { |curso| curso[:ruby] }.each do |curso| next if curso[:ruby] == ’rr-71’ puts "Curso de RoR na Caelum: #{ curso[:ruby] }" end 3.18 - Desafio: Usando blocos 1) Queremos imprimir as 7 cores do arco-íris apartir do seguinte código: ai = ArcoIris.new ai.each do |x| puts x end Crie a sua classe ArcoIris que ao ser invocada mostra as 7 cores do arco-íris. Tente lembrar dos conceitos de blocos e programação funcional para resolver. 3.19 - Mais OO Ruby também tem suporte a herança simples de classes: class Animal def come "comendo" end end Capítulo 3 - Ruby Avançado - Desafio: Usando blocos - Página 26 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails class Pato < Animal def quack "Quack!" end end pato = Pato.new pato.come # => "comendo" Classes filhas herdam todos os métodos definidos na classe mãe. A tipagem em Ruby não é explícita, por isso não precisamos declarar quais são os tipos dos atributos. Veja este exemplo: class PatoNormal def faz_quack "Quack!" end end class PatoEstranho def faz_quack "Queck!" end end class CriadorDePatos def castiga(pato) pato.faz_quack end end pato1 = PatoNormal.new pato2 = PatoEstranho.new c = CriadorDePatos.new c.castiga(pato1) # => "Quack!" c.castiga(pato2) # => "Queck!" Para o criador de patos, não interessa que objeto será passado como parâmetro. Para ele basta que o objeto saiba fazer quack. Esta característica da linguagem Ruby é conhecida como Duck Typing. “If it walks like a duck and quacks like a duck, I would call it a duck.” 3.20 - Modulos Modulos podem ser usados como namespaces: module Caelum module Validadores class ValidadorDeCpf Capítulo 3 - Ruby Avançado - Modulos - Página 27 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 3.23 - Arquivos Ruby Todos os arquivos fonte, contendo código Ruby devem ter a extensão .rb. Além disso, você pode dividir o código fonte em diversos arquivos e pastas. Para carregar o código Ruby de outro arquivo, basta usar o método require: require ’meu_outro_fonte’ puts ObjetoDefinidoFora.new.algum_metodo Caso a extensão .rb seja omitida, a extensão adequada será usada (.rb, .so, .class, .dll, etc). O Ruby procura pelo arquivo em alguns diretórios predefinidos (Ruby Load Path), incluindo o diretório atual. Caminhos relativos ou absolutos podem ser usados para incluir arquivos em outros diretórios: require ’modulo/funcionalidades/coisa_importante’ require ’/usr/local/lib/my/libs/ultra_parser’ A constante $:, ou $LOAD_PATH contém diretórios do Load Path: $: # => ["/Library/Ruby/Site/1.8", ..., "."] O comando require carrega o arquivo apenas uma vez. Para executar o conteúdo do arquivo diversas vezes, prefira o método load. load ’meu_outro_arquivo’ load ’meu_outro_arquivo’ # executado duas vezes! Capítulo 3 - Ruby Avançado - Arquivos Ruby - Página 30 CAPÍTULO 4 Ruby on Rails “A libertação do desejo conduz à paz interior” – Lao-Tsé 4.1 - Ruby On Rails - Apresentação David Heinemeier Hansson criou o Ruby on Rails para usar em um de seus projetos na empresa 37signals, o Basecamp. Desde então, passou a divulgar o código e incentivar o uso do mesmo. O Rails foi criado pensando na agilidade e praticidade que ele proporcionaria na hora de escrever os aplica- tivos para Web. Como pilares da agilidade em Rails, estão os conceitos de Don’t Repeat Yourself (DRY), e Convention over Configuration (CoC). O primeiro conceito diz que você não deve repetir código e sim modularizá-lo. Ou seja, você escreve trechos de código que serão reutilizáveis e evita o Copy And Paste de código. Já o segundo, diz que só devemos precisar fazer uma configuração nos casos excepcionais: ao utilizar os padrões oferecidos pelo Rails, você configura apenas o que estiver fora do padrão. A arquitetura de desenvolvimento em Rails é baseada no conceito de separar tudo em três camadas (Model View Controller ). MVC é um padrão arquitetural onde os limites entre seus modelos, suas lógicas e suas visualizações são bem definidos, sendo muito mais simples fazer um reparo, uma mudança ou uma manutenção. Meta-Framework Rails na verdade não é um framework, mas sim um conjunto de frameworks, alguns dos quais discutiremos adiante: • ActiveRecord • ActionPack (incluindo ActionController e ActionView) • ActiveSupport • ActiveResource • ActionMailer • ActiveWebServices (antigo e não mais incluído por padrão) 31 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Projetos que usam o Ruby on Rails Há uma extensa lista de aplicações que usam o Ruby on Rails e, entre elas estão o Twitter, Yellow- Pages.com, Typo (blog open source) e o Spokeo (ferramenta de agrupamento de sites de relacio- namentos). Uma lista completa de sites usando RubyOnRails com sucesso pode ser encontrada nestes dois endereços: http://rails100.pbwiki.com http://blog.obiefernandez.com/content/2008/03/big-name-compan.html 4.2 - Aprender Ruby? Ruby on Rails é escrito em Ruby, mas você não precisa conhecer tal linguagem para começar a programar com ele. Essa necessidade surge com o tempo, à medida que precisamos utilizar recursos mais complexos. Como vimos, a linguagem é dinâmica e interpretada, sendo que facilita o desenvolvimento das aplicações em alguns pontos básicos como, por exemplo, não obrigar o desenvolvedor a compilar o código ou a reiniciar um servidor para que a atualização feita entre no sistema. 4.3 - RadRails O Aptana RadRails é um ambiente de desenvolvimento integrado (Integrated Development Environment – IDE) criado por Kyle Shank para facilitar ainda mais o desenvolvimento para o Ruby On Rails. Existem diversas funções como execução de testes automatizados, suporte para debug, syntax highlighting, integração com diversas ferramentas, wizards, servidores, auto-complete, logs, perspectivas do banco de dados etc. O RadRails fornece tudo o que é preciso para desenvolver em Ruby on Rails: desde a criação do projeto até seu fechamento. Capítulo 4 - Ruby on Rails - Aprender Ruby? - Página 32 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails c) Escolha o nome “agenda” para seu projeto, selecione mysql como base de dados e aperte Finish. d) Verifique a view “console”. Note que o Rails já montou a estrutura do programa. Capítulo 4 - Ruby on Rails - Exercícios: Iniciando o Projeto - Página 35 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 4.6 - Estrutura dos diretórios Cada diretório tem uma função específica e bem clara na aplicação. Ao manter selecionado no wizard de criação do projeto a opção “Generate Rails application skeleton”, o Rails gera toda a estrutura do seu programa, criando os seguintes importantes diretórios: Capítulo 4 - Ruby on Rails - Estrutura dos diretórios - Página 36 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails • app -> 95% da aplicação e dos códigos criados ficam aqui (inclusive todo o MVC, dividido em diretórios). • config -> Configurações da aplicação. • db -> Banco de Dados, Migrações e Esquemas. • doc -> Documentação do sistema. • lib -> Bibliotecas. • log -> Informações de log. • public -> Arquivos públicos (CSS, imagens, etc), que serão servidos pela WEB. • script -> Scripts pré-definidos do Rails (console, server). • test -> Testes unitários, funcionais e de integração. • tmp -> Qualquer coisa temporária como, por exemplo, cache e informações de sessões. • vendor -> Plugins e programas externos. 4.7 - O Banco de Dados Uma das características do Rails é a facilidade de se comunicar com diversos bancos de modo transparente ao programador. Um exemplo dessa facilidade é que ao gerar a aplicação, ele criou também um arquivo de configuração do banco, pronto para se conectar ao MySQL. O arquivo está localizado em config/database.yml. Nada impede a alteração manual dessa configuração para outros tipos de bancos. Capítulo 4 - Ruby on Rails - O Banco de Dados - Página 37 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails c) Além disso, diversos arquivos são criados d) Também gera um arquivo para criação das tabelas no banco de dados e) E um arquivo routes.rb, que veremos mais adiante Capítulo 4 - Ruby on Rails - Exercícios: Scaffold - Página 40 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails f) (opcional) Criamos campos string, date e float. Quais outros tipos são suportados ? Abra a documentação do Rails (api.rubyonrails.org) e procure pela classe ActiveRecordConnectionAdaptersTable. 4.11 - Gerar as tabelas Já definimos o modelo e seus atributos, agora vamos executar o processo de geração das tabelas. Basta chamar o comando migrate que o rails executa o script de migração gerado pelo scaffold. O comando em questão é uma “Rake Task”. No próprio RadRails, existe uma view para execução desse tipo de comando, a “Rake Tasks”. Repare também que os campos no MySQL correspondem exatamente ao que foi definido no código de migração. O Rails gerou também, por conta própria, o campo id, fazendo o papel de chave primária de nossa tabela. Capítulo 4 - Ruby on Rails - Gerar as tabelas - Página 41 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 4.12 - Versão do Banco de Dados Ao chamar a Rake Task “migrate” pela primeira vez, será criada uma outra tabela chamada schema_migrations. Essa tabela contém uma única coluna (version), que indica quais foram as migrações executadas até agora, utilizando para isso o timestamp da última migration executada. Versões anteriores Nas versões anteriores do Rails, esta tabela se chamava schema_info e tinha apenas uma co- luna, com exatamente uma linha. Ela servia para indicar qual a versão do esquema do banco de dados que utilizávamos. Esse número era o mesmo que o começo do nome do arquivo do script de migração. No nosso caso, como possuímos um único script, o nome começaria com 001 (001_create_pessoas.rb) e a versão do banco também seria 1. Por exemplo, ao rodar a task de migração em um projeto que possui 20 scripts, cujo banco fora gerado ainda na versão 15, o Rails executaria os scripts 16, 17, 18, 19 e 20. Existe uma versão chamada 0, que retorna para o banco de dados em sua situação antes de ser atualizado pela primeira vez. Através dessa tarefa, também podemos voltar o esquema do banco de dados para versões anteriores, bastando indicar nos argumentos da tarefa qual a versão que desejamos utilizar. Quando voltamos a versões anteriores do esquema, o rake chama o método down do script, por isso é importante ter certeza que ele faz a operação inversa do método up. 4.13 - Exercícios: Migrar tabela 1) Migre a tabela para o banco de dados: a) Entre na view “Rake Tasks” b) Selecione a opção “db:migrate” c) Aperte “go” Capítulo 4 - Ruby on Rails - Versão do Banco de Dados - Página 42 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Este comando inicia um servidor WebRick na porta 8808. Basta acessar pelo browser para ver o RDoc de todos os gems instalados. A última alternativa é gerar a documentação através do rake: rails docs rake rails:freeze:gems rake rails:doc O truque é criar uma aplicação rails e congelar (freeze) o rails inteiro lá dentro. A operação freeze copia o código do rails para dentro da aplicação, na pasta vendor/rails. Depois de executar a task rails:doc, a documentação estará disponível no diretório docs/api/. A documen- tação do ruby (bem como a biblioteca padrão) pode ser encontrada em: http://ruby-doc.org Existem ainda excelentes guias e tutoriais oficiais disponíveis. É obrigatório para todo desenvolvedor Rails passar por estes guias: http://guides.rubyonrails.org Além desses guias, existe um site que lista as principais gems que podem ser usadas para cada tarefa: http://ruby-toolbox.com/ A comunidade Ruby e Rails também costuma publicar diversos excelentes screencasts (vídeos) com aulas e/ou palestras sobre diversos assuntos relacionados a Ruby e Rails. A lista está sempre crescendo, porém aqui estão alguns dos principais: • http://railscasts.com - vídeos pequenos e de graça, normalmente de 15min a 45min. Mantidos por Ryan Bates. • http://peepcode.com - vídeos maiores, verdadeiras vídeo-aulas; alguns chegam a 2h. São pagos, porém muitos consideram o valor simbólico (~$9 por vídeo). • http://www.confreaks.com - famosos por gravar diversas conferências sobre Ruby e Rails. • http://rubytu.be/ - reúne screencasts de diversas fontes. 4.16 - Exercício Opcional: Utilizando a documentação 1) Ao inserir uma nova pessoa, o campo ano apresentado no formulário mostra um ano muito atual. Como alterar ? Verifique no arquivo app/views/pessoas/new.html.erb que estamos usando um método chamado date_select: <%= f.date_select :data_de_nascimento %> Podemos procurar esse método na documentação, ele está em :ActionViewHelpersDateHelper e uma das opções que ele fornece é: • :start_year - Set the start year for the year select. Default is Time.now.year - 5. Capítulo 4 - Ruby on Rails - Exercício Opcional: Utilizando a documentação - Página 45 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Como utilizar essa informação? basta passar por hash, como abaixo: <%= f.date_select :data_de_nascimento, :start_year => 1970 %> Capítulo 4 - Ruby on Rails - Exercício Opcional: Utilizando a documentação - Página 46 CAPÍTULO 5 Active Record “Não se deseja aquilo que não se conhece” – Ovídio Nesse capítulo começaremos a desenvolver um sistema utilizando Ruby on Rails com recursos mais avan- çados do que os vistos anteriormente. 5.1 - Motivação Queremos criar um sistema de qualificação de restaurantes. Esse sistema terá clientes que qualificam os restaurantes visitados com uma nota, além de informar quanto dinheiro gastaram. Os clientes terão a possibilidade de deixar comentários para as qualificações feitas por eles mesmos ou a restaurantes ainda não visitados. Além disso, os restaurantes terão pratos, e cada prato a sua receita. O site http://www.tripadvisor.com possui um sistema similar para viagens, onde cada cliente coloca co- mentários sobre hotéis e suas visitas feitas no mundo inteiro. 5.2 - Exercícios: Controle de Restaurantes 1) Crie um novo projeto chamado “restaurante": a) Clique no primeiro botão abaixo do menu e escolha “Rails Project”. b) Digite “restaurante” para “Project Name”. 47 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 5.5 - Rake Rake é uma ferramenta de build, escrita em Ruby, e semelhante ao make e ao ant, em escopo e propósito. Rake tem as seguintes funcionalidades: • Rakefiles (versão do rake para os Makefiles) são completamente definidas em sintaxe Ruby. Não existem arquivos XML para editar, nem sintaxe rebuscada como a do Makefile para se preocupar. • É possível especificar tarefas com pré-requisitos. • Listas de arquivos flexíveis que agem como arrays, mas sabem como manipular nomes de arquivos e caminhos (paths). • Uma biblioteca de tarefas pré-compactadas para construir rakefiles mais facilmente. Para criar nossas bases de dados, podemos utilizar a rake task db:create:all. Para isso, vá para view Rake, escolha a opção db:create:all e clique em go. Repare que o Rails cria três bancos de dados: restaurante_development, restaurante_test e restau- rante_production. Para ver todas as tasks rake disponíveis no seu projeto podemos usar o comando (na raiz do seu projeto): rake -T Capítulo 5 - Active Record - Rake - Página 50 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 5.6 - Criando Modelos Agora iremos criar o modelo do Restaurante. Para isso, entre na View Generators, selecione a opção model e dê o nome restaurante para o modelo. Repare que o Rails gerou uma série de arquivos para nós. 5.7 - Migrations Migrations ajudam a gerenciar a evolução de um esquema utilizado por diversos bancos de dados. Foi a solução encontrada para o problema de como adicionar uma coluna no banco de dados local e propagar essa Capítulo 5 - Active Record - Criando Modelos - Página 51 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails mudança para os demais desenvolvedores de um projeto e para o servidor de produção. Com as migrations, podemos descrever essas transformações em classes que podem ser controladas por sistemas de controle de versão (por exemplo, SVN) e executá-las em diversos bancos de dados. Sempre que executarmos a tarefa Generator -> model, o Rails se encarrega de criar uma migration inicial, localizado em db/migrate. ActiveRecord::Migration é a classe que você deve estender ao criar uma migration. Quando geramos nosso modelo na seção anterior, Rails gerou para nós uma migration (db/migrate/<timestamp>_create_restaurantes.rb). Vamos agora editar nossa migration com as infor- mações que queremos no banco de dados. Queremos que nosso restaurante tenha um nome e um endereço. Para isso, devemos acrescentar: t.string :nome, :limit => 80 t.string :endereco Sua migration deve ter ficado parecida com esta: Capítulo 5 - Active Record - Migrations - Página 52 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 3) Edite seu script de migração do modelo “restaurante” para criar os campos nome e endereço: a) Abra o arquivo “db/migrate/<timestamp>_create_restaurantes.rb” b) Adicione as linhas: t.string :nome, :limit => 80 t.string :endereco 4) Migre as tabelas para o banco de dados: a) Abra a view Rake Tasks b) Escolha a opção “db:migrate” c) Aperte “go” d) Olhe no console o que foi feito e) Olhe no banco de dados mysql -u root use restaurante_development; desc restaurantes; Capítulo 5 - Active Record - Exercícios: Criando os modelos - Página 55 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 5) Adicione a coluna especialidade ao nosso modelo “restaurante": a) Abra a view “Generator” b) Escolha a opção “migration” c) De o nome “add_column_especialidade_restaurante” d) Aperte “go” e) Abra o arquivo “db/migrate/<timestamp>_add_column_especialidade_restaurante.rb” f) Adicione as linhas: def self.up add_column :restaurantes, :especialidade, :string, :limit => 40 end def self.down remove_column :restaurantes, :especialidade end Seu arquivo deve ter ficado assim: g) Abra a view “Rake Tasks” h) Escolha a opção “db:migrate” i) Aperte “go” j) Olhe no console o que foi feito Capítulo 5 - Active Record - Exercícios: Criando os modelos - Página 56 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails k) Olhe no banco de dados l) Utilizamos add_column e remove_column na nossa migration para adicionar uma nova co- luna. O que mais poderia ser feito ? Abra a documentação e procure pelo módulo ActiveRe- cordConnectionAdaptersSchemaStatements. 5.9 - Manipulando nossos modelos pelo console Podemos utilizar o console para escrever comandos Ruby, e testar nosso modelo. A grande vantagem disso, é que não precisamos de controladores ou de uma view para testar se nosso modelo funciona de acordo com o esperado e se nossas regras de validação estão funcionando. Outra grande vantagem está no fato de que se precisarmos manipular nosso banco de dados, ao invés de termos de conhecer a sintaxe sql e digitar a query manualmente, podemos utilizar código ruby e manipular através do nosso console. Para criar um novo restaurante, podemos utilizar qualquer um dos jeitos abaixo: r = Restaurante.new r.nome = "Fasano" r.endereco = "Av. dos Restaurantes, 126" r.especialidade = "Comida Italiana" r.save r = Restaurante.new do |r| r.nome = "Fasano" r.endereco = "Av. dos Restaurantes, 126" r.especialidade = "Comida Italiana" end r.save r = Restaurante.new :nome => "Fasano", :endereco => "Av. dos Restaurantes, 126", :especialidade => "Comida Italiana" r.save Restaurante.create :nome => "Fasano", :endereco => "Av. dos Restaurantes, 126", :especialidade => "Comida Italiana" Repare que o create já salva o novo restaurante no banco de dados, não sendo necessário o comando save. Note que o comando save efetua a seguinte ação: se o registro não existe no banco de dados, cria um novo registro; se já existe, atualiza o registro existente. Capítulo 5 - Active Record - Manipulando nossos modelos pelo console - Página 57 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 5.11 - Exercícios Opcionais 1) Teste outras maneiras de efetuar as operações do exercício anterior. 5.12 - Finders O ActiveRecord possui o método “find” para realizar buscas. Esse método, aceita os seguintes parâmetros: Restaurante.find(:all) # retorna todos os registros Restaurante.find(:first) # retorna o primeiro registro Restaurante.find(:last) # retorna o último registro Existem também atalhos para estes tipos de find: Restaurante.all Restaurante.first Restaurante.last Ainda podemos passar para o método find uma lista com os id’s dos registros que desejamos: r = Restaurante.find(1) varios = Restaurante.find(1,2,3) Além desses, podemos definir condições para nossa busca (como o SELECT do MySQL). Existem diversas formas de declararmos essas condições: :conditions => "bla = 1 and xpto = 3" :conditions => ["bla = ? and xpto = ?", 1, 3] :conditions => ["bla = :b and xpto = :c", {:b => 1, :c => 3}] :conditions => { :bla => 1, :xpto => 3 }] Essas quatro formas fazem a mesma coisa. Procuram por registros com o campo bla = 1 e o campo xpto = 3. Existem ainda os chamados dynamic finders: Restaurante.find(:all, :conditions => ["nome = ? AND especialidade = ?", "Fasano", "italiana"]) poderia ser escrito como: find_all_by_nome_and_especialidade("Fasano", "italiana") Temos ainda o “find_or_create_by”, que retorna um objeto se ele existir, caso contrário, cria o objeto no banco de dados e retorna-o: Restaurante.find_or_create_by_nome("Fasano") Para finalizar, o método find aceita ainda outras opções: • :order - define a ordenação. Ex: “created_at DESC, nome”. • :group - nome do atributo pelo qual os resultados serão agrupados. Efeito idêntico ao do comando SQL GROUP BY. Capítulo 5 - Active Record - Exercícios Opcionais - Página 60 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails • :limit - determina o limite do número de registros que devem ser retornados • :offset - determina o ponto de início da busca. Ex: para offset = 5, iria pular os registros de 0 a 4. • :include - permite carregar relacionamentos na mesma consulta usando LEFT OUTER JOINS. Para Sabe Mais - Outras opções para os finders Existem mais opções, como o “:lock”, que podem ser utilizadas, mas não serão abordadas nesse curso. Você pode consultá-las na documentação da API do Ruby on Rails. 5.13 - Exercícios: Buscas dinâmicas 1) Vamos testar os métodos de busca: a) Abra o console (ruby script/console) b) Digite: Restaurante.find(:first) c) Aperte enter d) Digite: Restaurante.find(:all) e) Aperte enter f) Digite: Restaurante.find(1) g) Aperte enter h) Digite: Restaurante.find(:all, :conditions => ["nome = ? AND especialidade = ?", "Fasano", "Comida Italiana"]) i) Aperte enter j) Digite: Restaurante.find_all_by_nome_and_especialidade("Fasano", "Comida Italiana") k) Aperte enter l) Digite: Restaurante.find(:all, :order => "especialidade DESC", :limit => 1) m) Aperte enter Capítulo 5 - Active Record - Exercícios: Buscas dinâmicas - Página 61 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 5.14 - Validações Ao inserir um registro no banco de dados é bem comum a entrada de dados inválidos. Existem alguns campos de preenchimento obrigatório, outros que só aceitem números, que não podem conter dados já existentes, tamanho máximo e mínimo etc. Para ter certeza que um campo foi preenchido antes de salvar no banco de dados, é necessário pensar em três coisas: “como validar a entrada?”, “qual o campo a ser validado?” e “o que acontece ao tentar salvar uma entrada inválida?”. Para validar esses registros, podemos implementar o método validate em qualquer ActiveRecord, porém o Rails disponibiliza alguns comandos prontos para as validações mais comuns. São eles: • validates_presence_of: verifica se um campo está preenchido; • validates_size_of: verifica o comprimento do texto do campo; • validates_uniqueness_of: verifica se não existe outro registro no banco de dados que tenha a mesma informação num determinado campo; • validates_numericality_of: verifica se o preenchimento do campo é numérico; • validates_associated: verifica se o relacionamento foi feito corretamente; • etc... Todos estes métodos disponibilizam uma opção (:message) para personalizar a mensagem de erro que será exibida caso a regra não seja cumprida. Caso essa opção não seja utilizada, será exibida uma mensagem padrão. Toda mensagem de erro é gravada num hash chamado errors, presente em todo ActiveRecord. Além dos validadores disponibilizados pelo rails, podemos utilizar um validador próprio: validate :garante_alguma_coisa def garante_alguma_coisa errors.add_to_base("Deve respeitar nossa regra") unless campo_valido? end Repare que aqui, temos que incluir manualmente a mensagem de erro padrão do nosso validador. Se quisermos que o nome do nosso restaurante comece com letra maiúscula, poderíamos fazer: validate :primeira_letra_deve_ser_maiuscula private def primeira_letra_deve_ser_maiuscula errors.add("nome", "primeira letra deve ser maiúscula") unless nome =~ /[A-Z].*/ end Modificadores de acesso Utilizamos aqui, o modificador de acesso private. A partir do ponto que ele é declarado, todos os métodos daquela classe serão privados, a menos que tenha um outro modificador de acesso que modifique o acesso a outros métodos. Capítulo 5 - Active Record - Validações - Página 62 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 2) Vamos agora fazer as validações no modelo “cliente”: a) Abra o arquivo “app/models/cliente.rb” b) Adicione as seguintes linhas: validates_presence_of :nome, :message => " - deve ser preenchido" validates_uniqueness_of :nome, :message => " - name já cadastrado" validates_numericality_of :idade, :greater_than => 0, :less_than => 100, :message => " - deve ser um número entre 0 e 100" 3) Vamos criar o modelo Prato, bem como sua migration: a) Entre na view “Generator” b) Escolha a opção “model” c) Digite o nome “prato” d) Clique em “go” e) Abra o arquivo “db/migrate/<timestamp>_create_pratos.rb” f) Adicione as linhas: t.string :nome, :limit => 80 g) Abra a view “Rake Tasks” h) Escolha a opção “db:migrate” i) Aperte “go” Capítulo 5 - Active Record - Exercícios - Completando nosso modelo - Página 65 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails j) Olhe no console o que foi feito k) Olhe no banco de dados! 4) Vamos agora fazer as validações no modelo “prato”: a) Abra o arquivo “app/models/prato.rb” b) Adicione as seguintes linhas: validates_presence_of :nome, :message => " - deve ser preenchido" validates_uniqueness_of :nome, :message => " - nome já cadastrado" 5) Vamos criar o modelo Receita, bem como sua migration: a) Entre na view “Generator” b) Escolha a opção “model” c) Digite o nome “receita” d) Clique em “go” e) Abra o arquivo “db/migrate/<timestamp>_create_receitas.rb” f) Adicione as linhas: t.text :conteudo g) Abra a view “Rake” h) Escolha a opção “db:migrate” i) Aperte “go” j) Olhe no console o que foi feito k) Olhe no banco de dados! 6) Vamos agora fazer as validações no modelo “receita”: a) Abra o arquivo “app/models/receita.rb” b) Adicione as seguintes linhas: validates_presence_of :conteudo, :message => " - deve ser preenchido" 5.17 - O Modelo Qualificação Antes de criarmos nosso modelo de Qualificação, repare que o Rails pluraliza os nomes de nossos modelos de forma automática. Por exemplo, o nome da tabela do modelo Cliente ficou clientes. No entanto, qualificacao é uma palavra que tem sua pluralização irregular (não basta adicionar um ‘s’ no final da palavra), e o Rails deve gerar a seguinte palavra pluralizada: ‘qualificacaos’, uma vez que estamos utilizando o português e ele possui regras de pluralização apenas para o inglês. Para corrigir isso, vamos ter de editar o arquivo “config/initializers/inflections.rb” e inserir manualmente o plural da palavra ‘qualificacao’. Repare que nesse mesmo arquivo temos diversos exemplos comentados de como podemos fazer isso. Quando inserirmos as linhas abaixo no final do arquivo, o Rails passará a utilizar esse padrão para a plura- lização: Capítulo 5 - Active Record - O Modelo Qualificação - Página 66 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails ActiveSupport::Inflector.inflections do |inflect| inflect.irregular ’qualificacao’, ’qualificacoes’ end 5.18 - Exercícios - Criando o Modelo de Qualificação 1) Vamos corrigir a pluralização da palavra ‘qualificacao’ a) Abra o arquivo “config/initializers/inflections.rb” b) Adicione as seguintes linhas ao final do arquivo: ActiveSupport::Inflector.inflections do |inflect| inflect.irregular ’qualificacao’, ’qualificacoes’ end brazilian-rails Existe um plugin chamado Brazilian Rails que é um conjunto de gems para serem usadas com Ruby e com o Ruby on Rails e tem como objetivo unir alguns recursos úteis para os desenvolvedores brasileiros. 2) Vamos continuar com a criação do nosso modelo Qualificacao e sua migration. a) Entre na view “Generator” b) Escolha a opção “model” c) Digite o nome “qualificacao” d) Clique em “go” e) Abra o arquivo “db/migrate/<timestamp>_create_qualificacoes.rb” Capítulo 5 - Active Record - Exercícios - Criando o Modelo de Qualificação - Página 67 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Para relacionar diversos modelos, precisamos informar ao Rails o tipo de relacionamento entre eles. Quando isso é feito, alguns métodos são criados para podermos manipular os elementos envolvidos nesse relaciona- mento. Os relacionamentos que Rails disponibiliza são os seguintes: • belongs_to - usado quando um modelo tem como um de seus atributos o id de outro modelo (many-to-one ou one-to-one). Quando dissermos que uma qualificação belongs_to um restaurante, ainda ganharemos os seguintes métodos: – Qualificacao.restaurante (similar ao Restaurante.find(restaurante_id)) – Qualificacao.restaurante=(restaurante) (similar ao qualificacao.restaurante_id = restaurante.id) – Qualificacao.restaurante? (similar ao qualificacao.restaurante == algum_restaurante) • has_many - associação que provê uma maneira de mapear uma relação one-to-many entre duas entida- des. Quando dissermos que um restaurante has_many qualificações, ganharemos os seguintes métodos: Capítulo 5 - Active Record - Relacionamentos - Página 70 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails – Restaurante.qualificacoes (semelhante ao Qualificacao.find :all, :conditions => ["restaurante_id = ?”, id]) – Restaurante.qualificacoes<< – Restaurante.qualificacoes.delete – Restaurante.qualificacoes= • has_and_belongs_to_many - associação muitos-para-muitos, que é feita usando uma tabela de mapea- mento. Quando dissermos que um prato has_and_belongs_to_many restaurantes, ganharemos os seguintes métodos: – Prato.restaurantes – Prato.restaurantes<< – Prato.restaurantes.delete – Prato.restaurantes= Além disso, precisaremos criar a tabela pratos_restaurantes, com as colunas prato_id e restau- rante_id. Por convenção, o nome da tabela é a concatenação do nome das duas outras tabelas, seguindo a ordem alfabética. • has_one - lado bidirecional de uma relação um-para-um. Quando dissermos que um prato has_one receita, ganharemos os seguintes métodos: – Prato.receita, (semelhante ao Receita.find(:first, :conditions => “prato_id = id”)) – Prato.receita= 5.20 - Para Saber Mais: Auto-relacionamento Os relacionamentos vistos até agora foram sempre entre dois objetos de classes diferentes. Porém existem relacionamentos entre classes do mesmo tipo, por exemplo, uma Categoria de um site pode conter outras cate- gorias, onde cada uma contém ainda suas categorias. Esse relacionamento é chamado auto-relacionamento. No ActiveRecord temos uma forma simples para fazer essa associação. class Category < ActiveRecord::Base has_many :children, :class_name => "Category", :foreign_key => "father_id" belongs_to :father, :class_name => "Category" end 5.21 - Para Saber Mais: Cache Todos os resultados de métodos acessados de um relacionamento são obtidos de um cache e não nova- mente do banco de dados. Após carregar as informações do banco, o ActiveRecord só volta se ocorrer um pedido explicito. Exemplos: restaurante.qualificações # busca no banco de dados restaurante.qualificações.size # usa o cache restaurante.qualificações.empty? # usa o cache restaurante.qualificações(true).size # força a busca no banco de dados restaurante.qualificações # usa o cache Capítulo 5 - Active Record - Para Saber Mais: Auto-relacionamento - Página 71 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 5.22 - Exercícios - Relacionamentos 1) Vamos incluir os relacionamentos necessários para nossos modelos: a) Abra o arquivo “app/models/cliente.rb” b) Adicione a seguinte linha: has_many :qualificacoes c) Abra o arquivo “app/models/restaurante.rb” d) Adicione a seguinte linha: has_many :qualificacoes has_and_belongs_to_many :pratos e) Abra o arquivo “app/models/qualificacao.rb” f) Adicione as seguintes linhas: belongs_to :cliente belongs_to :restaurante Capítulo 5 - Active Record - Exercícios - Relacionamentos - Página 72 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails 4) Faça alguns testes no terminal para testar essas novas validações. 5.23 - Para Saber Mais - Eager Loading Podemos cair em um problema grave caso o número de qualificações para um restaurante seja muito grande. Imagine que um determinado restaurante do nosso sistema possua com 100 qualificações. Queremos mostrar todas as qualificações desse restaurante, então fazemos um for: for qualificacao in Qualificacaoes.all puts "restaurante " + qualificacao.restaurante.nome puts "restaurante " + qualificacao.cliente.nome puts "qualificacao: " + qualificacao.nota end Para iterar sobre as 100 qualificações do banco de dados, seriam geradas 201 buscas! Uma busca para to- das as qualificações, 100 buscas para cada restaurante mais 100 buscas para cada cliente! Podemos melhorar um pouco essa busca. Podemos pedir ao ActiveRecord que inclua o restaurante quando fizer a busca: Qualificacoes.find(:all, :include => :restaurante) Bem melhor! Agora a quantidade de buscas diminuiu para 102! Uma busca para as qualificações, outra para todos os restaurantes e mais 100 para os clientes. Podemos utilizar a mesma estratégia para otimizar a busca de clientes: Qualificacoes.find(:all, :include => [ :restaurante, :cliente ]) Com essa estratégia, teremos o número de buscas muito reduzido. A quantidade total agora será de 1 + o número de associações necessárias. Poderíamos ir mais além, e trazer uma associação de uma das associações existentes em qualificação: Qualificacoes.find(:all, :include => [ :cliente, { :restaurante => { :prato => :receita } } ]) 5.24 - Para Saber Mais - Named Scopes Para consultas muito comuns, podemos usar o recurso de Named Scopes oferecido pelo ActiveRecord, que permite deixarmos alguns tipos de consultas comuns “preparadas”. Imagine que a consulta de restaurantes de especialidade “massa” seja muito comum no nosso sistema. Podemos facilitá-la criando um named scope na classe Restaurante: class Restaurante < ActiveRecord::Base named_scope :massas, :conditions => { :especialidade => ’massas’ } end As opções mais comuns do método find também estão disponíveis para named scopes, como :conditions, :order, :select e :include. Com o named scope definido, a classe ActiveRecord ganha um método de mesmo nome, através do qual podemos recuperar os restaurantes de especialidade "massas" de forma simples: Restaurante.massas Restaurante.massas.first Capítulo 5 - Active Record - Para Saber Mais - Eager Loading - Página 75 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Restaurante.massas.last Restaurante.massas.find(:all, :conditions => ["nome like ?", ’%x%’]) O método associado ao named scope criado retorna um objeto da classe ActiveRecordNamedScope Scope, que age como um Array, mas aceita a chamada de alguns métodos das classes ActiveRecord, como o find para filtrar ainda mais a consulta. Podemos ainda definir diversos named scopes e combiná-los de qualquer forma: class Restaurante < ActiveRecord::Base named_scope :massas, :conditions => { :especialidade => ’massas’ } named_scope :recentes, :conditions => [ "created_at > ?", 3.months.ago ] named_scope :pelo_nome, :order => ’nome’ end Restaurante.massas # todos de especialidade = ’massas’ Restaurante.recentes # todos de created_at > 3 meses atras # especialidade = ’massas’ e created_at > 3 meses atras Restaurante.massas.recentes Restaurante.recentes.massas Restaurante.massas.pelo_nome.recentes 5.25 - Para Saber Mais - Modules As associações procuram por relacionamentos entre classes que estejam no mesmo módulo. Caso precise de relacionamentos entre classes em módulos distintos, é necessário informar o nome completo da classe no relacionamento: module Restaurante module RH class Pessoa < ActiveRecord::Base; end end module Financeiro class Pagamento < ActiveRecord::Base belongs_to :pessoa, :class_name => "Restaurante::RH::Pessoa" end end end Capítulo 5 - Active Record - Para Saber Mais - Modules - Página 76 CAPÍTULO 6 Controllers e Views “A Inteligência é quase inútil para quem não tem mais nada” – Carrel, Alexis Nesse capítulo, você irá aprender o que são controllers e como utilizá-los para o benefício do seu projeto, além de aprender a trabalhar com a camada visual de sua aplicação. 6.1 - O “V” e o “C” do MVC O “V” de MVC representa a parte de view (visualização) da nossa aplicação, sendo ela quem tem contato com o usuário, recebe as entradas e mostra qualquer tipo de saída. Há diversas maneiras de controlar as views, sendo a mais comum delas feita através dos arquivos HTML.ERB, ou eRuby (Embedded Ruby), páginas HTML que podem receber trechos de código em Ruby. Controllers são classes que recebem uma ação de uma View e executam algum tipo de lógica ligada a um ou mais modelos. Em Rails esses controllers estendem a classe ApplicationController. As urls do servidor são mapeadas da seguinte maneira: /controller/action/id. Onde “controller” representa uma classe controladora e “action” representa um método do mesmo. “id” é um parâmetro qualquer (opcional). 6.2 - Hello World Antes de tudo criaremos um controller que mostrará um “Hello World” para entender melhor como funciona essa idéia do mapeamento de urls. Entre na view generators, escolha a opção controller e digite o nome “HelloWorld”. Veja que o Rails não gera apenas o Controller, mas também outros arquivos. 77 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Ao invés de fazer o redirecionamento, podemos chamar outra action diretamente. Assim não vamos ser redirecionados e a URL continuará a mesma. def index hello end Redirecionamento no servidor e no cliente O redirecionamento no servidor é conhecido como forward e a requisição é apenas repassada a um outro recurso (página, controlador) que fica responsável em tratar a requisição. Há uma outra forma que é o redirecionamento no cliente (redirect). Nesta modalidade, o servidor responde a requisição original com um pedido de redirecionamento, fazendo com que o nave- gador dispare uma nova requisição para o novo endereço. Neste caso, a barra de endereços do navegador muda. 6.5 - Trabalhando com a View: O ERB ERb ERb é uma implementação de eRuby que já acompanha a linguagem Ruby. Seu funcionamento é similar ao dos arquivos JSP/ASP: arquivos html com injeções de código. A idéia é que o HTML serve como um template, e outros elementos são dinâmicamente inseridos em tempo de renderização. Para uma página aceitar código Ruby, ela deve estar entre “<%” e “%>”. Há uma variação deste operador, o “<%=”, que não só executa códigos Ruby, mas também imprime o resultado na página HTML. Existe ainda o “<%=h”, que traduz qualquer caracter estranho (“<”, “>”, “"”, “”’, etc) para seu código HTML equivalente. É importante notar, que todos os atributos de instância (@variavel) de um controlador estão disponíveis em sua view. Além disso, a view deve ter o mesmo nome do controlador, o que significa que a view da nossa action index do controlador restaurantes_controller.rb deve estar em app/views/restaurantes/index.html.erb. Podemos começar precisamos que uma view seja renderizada para pegar os valores de um novo restau- rante. (Essa view será apresentada após o código da action new, que faremos mais a frente): <form action=’/restaurantes/create’> Nome: <input type=’text’ name=’nome’/> <input type=’submit’ value=’Create’/> </form> E agora, para receber este valor no controlador, basta usar o hash params. (Repare que agora usamos outra action, create, para buscar os dados do formulário apresentado anteriormente): class RestaurantesController < ApplicationController def create nome = params[’nome’] end end O problema desta abordagem é que precisaríamos recuperar os valores enviados pelo formulário, um a um. Para um formulário com 15 campos, teríamos 15 linhas apenas para recuperar as informações submetidas! Capítulo 6 - Controllers e Views - Trabalhando com a View: O ERB - Página 80 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Para simplificar esta tarefa, o Rails oferece a possibilidade de utilizar algo parecido com um hash para os valores dos atributos: <form action=’/restaurantes/create’> Nome: <input type=’text’ name=’restaurante[nome]’ /> Endereço: <input type=’text’ name=’restaurante[endereco]’ /> Especialidade: <input type=’text’ name=’restaurante[especialidade]’ /> <input type=’submit’ value=’Create’/> </form> Desta forma, podemos receber todos os valores como um hash nos controladores: class RestaurantesController < ApplicationController def create valores = params[’restaurante’] end end O mais interessante é que as classes ActiveRecord já aceitam um hash com os valores iniciais do objeto, tanto no método new, no método create (que já salva), quanto no método update_attributes: Restaurante.create(params[’restaurante’]) 6.6 - Entendendo melhor o CRUD Agora, queremos ser capazes de criar, exibir, editar e remover restaurantes. Como fazer? Primeiro, temos de criar um controller para nosso restaurante: Pela view Generators, vamos criar um controller para restaurante. Rails, por padrão, utiliza-se de sete actions “CRUD”. São eles: • list: exibe todos os items • show: exibe um item específico • new: formulário para a criação de um novo ítem • create: cria um novo ítem • edit: formulário para edição de um ítem • update: atualiza um ítem existente • destroy: remove um ítem existente Desejamos listar todos os restaurantes do nosso Banco de Dados, e portanto criaremos a action list. Como desejamos que o comportamento padrão do nosso controlador restaurante seja exibir a listagem de restaurantes, podemos renomeá-la para index. Assim como no console buscamos todos os restaurantes do banco de dados com o comando find, também podemos fazê-lo em controllers (que poderão ser acessados pelas nossas views, como veremos mais adiante). Basta agora passar o resultado da busca para uma variável: Capítulo 6 - Controllers e Views - Entendendo melhor o CRUD - Página 81 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails def index @restaurantes = Restaurante.find(:all, :order => "nome") end Para exibir um restaurante específico, precisamos saber qual restaurante buscar. Essa informação vem no “id” da url, e contem o id do restaurante que desejamos. Para acessá-la, podemos usar como parâmetro do método find params[id], que recupera as informações passadas no id da url. Agora, podemos criar nossa action show: def show @restaurante = Restaurante.find(params[:id]) end Para incluir um novo restaurante, precisamos primeiro retornar ao browser um restaurante novo, sem infor- mação alguma. Vamos criar nossa action new def new @restaurante = Restaurante.new end Uma vez que o usuário do nosso sistema tenha preenchido as informações do novo restaurante e deseje salvá-las, enviará uma requisição à nossa action create, passando como parâmetro na requisição, o novo restaurante a ser criado. Vamos criar nossa action: def create @restaurante = Restaurante.new(params[:restaurante]) @restaurante.save end Para editar um restaurante, devemos retornar ao browser o restaurante que se quer editar, para só depois salvar as alterações feitas: def edit @restaurante = Restaurante.find(params[:id]) end Uma vez que o usuário tenha atualizado as informações do restaurante e deseje salvá-las, enviará uma requisição à nossa action update passando no id da url o id do restaurante a ser editado, bem como o restaurante que será “colado” em seu lugar: def update @restaurante = Restaurante.find(params[:id]) @restaurante.update_attributes(params[:restaurante]) end Para remover um restaurante, o usuário enviará uma requisição à nossa action destroy passando no id da url o id do restaurante a ser excluído: def destroy @restaurante = Restaurante.find(params[:id]) @restaurante.destroy end Capítulo 6 - Controllers e Views - Entendendo melhor o CRUD - Página 82 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails • hidden_field_tag • image_submit_tag • password_field_tag • radio_button_tag • select_tag • submit_tag • text_area_tag • text_field_tag Agora, podemos reescrever nossa view: <% form_tag :action => ’create’ do %> Nome: <%= text_field :restaurante, :nome %> Endereço: <%= text_field :restaurante, :endereco %> Especialidade: <%= text_field :restaurante, :especialidade %> <%= submit_tag ’Create’ %> <% end %> Repare que como utilizamos o form_tag, que não está associado a nenhum ActiveRecord, nosso outro Helper text_field não sabe qual o ActiveRecord que estamos trabalhando, sendo necessário passar para cada um deles o parâmetro :restaurante, informando-o. Podemos reescrever mais uma vez utilizando o FormHelper form_for, que está associado a um ActiveRecord: <% form_for :restaurante, :url => { :action => ’create’ } do |f| %> Nome: <%= f.text_field :nome %> Endereço: <%= f.text_field :endereco %> Especialidade: <%= f.text_field :especialidade %> <%= submit_tag ’Create’ %> <% end %> Repare agora que não foi preciso declarar o nome do nosso modelo para cada text_field, uma vez que nosso Helper form_for já está associado a ele. Por último, poderíamos querer ver possíveis mensagens com problemas de validação. O módulo ActionViewHelpers ActiveRecordHelpers contém o helper error_messages_for, que recebe o nome do modelo do qual serão exibidos todos os problemas de validação, caso existam. <%= error_messages_for :restaurante %> Capítulo 6 - Controllers e Views - Helper - Página 85 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails Helper Method Existe também o chamado helper_method, que permite que um método de seu controlador vire um Helper e esteja disponível na view para ser chamado. Exemplo: class TesteController < ApplicationController helper_method :teste def teste "algum conteudo dinamico" end end E em alguma das views deste controlador: <%= teste %> 6.9 - Exercícios: Utilizando helpers para criar as views 1) Vamos criar as views do restaurante: a) Crie o arquivo app/views/restaurantes/index.html.erb. Você pode clicar com o botão direito do mouse em app/views/restaurantes e escolher a opção New => ERB/RHTML File, ou dentro do corpo da action index, pressionar “Ctrl+Shift+V”. Em ambos os casos, escolha o nome index.html.erb b) Digite o conteúdo abaixo: <h1>Listagem de Restaurantes</h1> <table> <tr> <th>Nome</th> <th>Endereço</th> <th>Especialidade</th> </tr> <% for restaurante in @restaurantes %> <tr> <td><%=h restaurante.nome %></td> <td><%=h restaurante.endereco %></td> <td><%=h restaurante.especialidade %></td> <td><%= link_to ’Show’, { :action => ’show’, :id => restaurante } %></td> <td><%= link_to ’Edit’, { :action => ’edit’, :id => restaurante } %></td> <td><%= link_to ’Destroy’, { :action => ’destroy’, :id => restaurante } %></td> </tr> <% end %> </table> <br/> <%= link_to ’New’, { :action => ’new’ } %> Capítulo 6 - Controllers e Views - Exercícios: Utilizando helpers para criar as views - Página 86 Material do Treinamento Desenvolvimento Ágil para Web 2.0 com Ruby on Rails c) Teste agora entrando em: http://localhost:3000/restaurantes (talvez seja necessário reiniciar o servidor) d) Crie o arquivo app/views/restaurantes/show.html.erb e) Digite o conteúdo abaixo: <h1>Exibindo Restaurante</h1> <p> <b>Nome: </b> <%=h @restaurante.nome %> </p> Capítulo 6 - Controllers e Views - Exercícios: Utilizando helpers para criar as views - Página 87
Docsity logo



Copyright © 2024 Ladybird Srl - Via Leonardo da Vinci 16, 10126, Torino, Italy - VAT 10816460017 - All rights reserved