Entendendo Rails Fabio Akita Surgeworks Brazil Rails Practice Manager www.akitaonrails.com 37signals • Criado por David Heinemeier Hansson, em 2004 • Extraído do aplicativo Basecamp • Feito em Ruby, em vez de PHP ou Java • Lançamento da versão 1.0 em dez/2005 O que é Rails? • “full stack web framework” • Framework completo para desenvolvimento de aplicativo Web • Pacote MVC (Model-View-Controller) – Action Pack (Action Controller e Action View) – Active Record • Suporte a envio e recebimento de e-mails – Action Mailer • Suporte a Web Services – Action WebServices Arquitetura Rails Por que Ruby? • • • • • • • • • Linguagem Dinâmica Fortemente Tipada Muito Expressiva Altamente Produtiva Totalmente Orientado a Objetos Herança de SmallTalk e Lisp Simples sem ser complexa Sintaxe familiar e coerente Permite criação de Linguagem Específica de Domínio (DSL) Começo Simples • Windows: Instant Rails – wiki.rubyonrails.com/rails/pages/InstantRails • Mac e Linux: – FiveRuns RB-Install • www.fiveruns.com/products/rm/install Começo Padrão • Instalar Ruby 1.8.6 – www.ruby-lang.org/en/downloads • Instalar RubyGems (Mac ou Linux) – rubyforge.org/frs/?group_id=126 • Instalar Rails (linha de comando) – gem install rails • Instalar MySQL (suporta outros bancos) – dev.mysql.com/downloads Primeiro Passo • Saber o que queremos: – David Hansson tem um screencast demonstrando a criação de um pequeno blog em 15 minutos – http://media.rubyonrails.org/video/rails_take2_with_sound.mov • Queremos um blog semelhante O Que temos no Blog? • • • • • • Uma tabela de Posts Uma tabela associada de Comments Uma tela de listagem de Posts Uma tela de criação e edição de Posts Uma tela de detalhes do Post No detalhe do Post vemos e adicionamos Comments • Faremos tudo em inglês. Não é difícil adaptar para Português, mas não é escopo desta demonstração Novo Projeto • rails <projeto> Novo Banco de Dados • create database <projeto>_<ambiente> Ambientes • Rails vem preparado para lidar com três ambientes diferentes: – Development (sandbox) – Test (testes unitários, funcionais, integrados) – Production (produção) Convenção sobre Configuração • Estrutura comum de diretórios Configuração Mínima • Banco de dados • No exemplo, apenas colocando as senhas Criando um Controller • script/generate controller <nome> Controllers e Actions • Todo Controller fica no diretório: – /app/controllers/<nome>_controller.rb • Todo Controller herda a classe ApplicationController • Todo aplicativo Rails é criado com uma classe chamada ApplicationController, que herda de ActionController::Base, e é base de todos os outros controllers • Todo método de um controller é chamado de Action Criando uma Action • Uma classe Controller pode ter quantas Actions quanto necessárias Servidor de Teste: WEBRick Roteamento Customizável • http://localhost:3000/:controller/:action/:id Acessando uma Action • Seguindo a regra anterior de roteamento – http://localhost:3000/blog/index – blog = app/controller/blog_controller.rb – index = método index em BlogController Criando uma View Mais Convenções • Ao final de toda Action, Rails chamará uma view com o mesmo nome da Action, no seguinte diretório: – /app/views/<controller>/<action>.<ext> • A extensão do arquivo pode ser: – .rhtml - Embedded Ruby (HTML+Ruby) – .rxml - XML Builder (Ruby puro) – .rjs - Javascript Generator (Ruby puro) • Este fluxo pode ser interrompido com uma chamada explícita ao método render ou redirect_to Implementando Post • script/generate model <nome> Migration • Manutenção de tabelas usando Ruby • Independente de banco • Mas também suporta SQL nativo Rake: Ruby Make • Execução de tarefas, implementadas em Ruby • Primeira tarefa: manutenção das tabelas rake migrate • Toda entidade criada com script/generate gera um arquivo de Migration no diretório db/migrate • Todo arquivo Migration é numerado: – 001_create_posts.rb • O comando rake migrate executa os arquivos em db/migrate • Usa a tabela schema_info no banco de dados para saber a partir de qual numeração começar • O gerenciamento do banco de dados é feito totalmente em Ruby Mapeando Tabelas • A classe Post já é capaz de gerenciar os dados da tabela no banco de dados • Não há necessidade de explicitar o mapeamento das colunas do banco com atributos da classe • Rails não proíbe nada: se for necessário existe como mapear uma coluna para outro atributo de nome diferente Convenções de Entidades • Toda entidade é criada no diretório padrão: – /app/models/<controller>/<model>.rb • Toda entidade herda diretamente da classe ActiveRecord::Base • Não há necessidade de mapear manualmente cada coluna da tabela • Convenção: a classe tem o nome no singular (Post), a tabela tem o nome do plural (posts) • Convenção: Surrogate Key, toda tabela tem uma chave primária chamada “id” que é um número autoincrementável annotate_models annotate_models • Plugin de Dave Thomas • Instalação (via internet): – script/plugin install annotate_models • Utilização (via rake): – rake annotate_models • Lê a tabela do banco de dados e coloca um cabeçalho como comentário na classe entidade Scaffold Scaffold • Colocar o método scaffold :<model> no controller é suficiente • Telas CRUD (Create, Read, Update, Delete) geradas automaticamente em tempo de execução (runtime) • CUIDADO: Rails NÃO é Scaffold • Scaffold é apenas uma pequena funcionalidade para facilitar prototipação Configurando Post • Acrescentando validação Testando modificação • Não é necessário reiniciar servidor Incrementando Post • Criando novas colunas com Migration • script/generate migration <atividade> Executando Migration Criando um Post • Novamente, sem reiniciar o servidor Gerando o Scaffold • script/generate scaffold <model> <controller> Arquivos Gerados • Toda execução automática de antes agora está exposta em arquivos que podemos editar como quisermos • Provado: Rails não se restringe a Scaffold automático Modificando a Listagem • /app/views/blog/list.rhtml Testando a listagem • http://localhost:3000/blog • Portanto, podemos alterar o layout ou qualquer código como quisermos Polêmica do Scriplet • Rails não utiliza taglibs • Ruby é simples e expressiva o suficiente para não precisar de artifícios • Taglibs são simplificações de lógica • Podemos fazer tudo de maneira simples e flexível sem precisar aprender sintaxes complexas de XML Exemplos Taglibs Scriptlets <logic:iterate id=”post" collection="<%=posts%>"> <% @posts.each do |post| %> Faz alguma coisa com post <% end %> Faz alguma coisa com post </logic:iterate> <logic:equal parameter="number" value="7"> <% if number == "7" %> Está correto! <% end %> Está correto! </logic:equal> Portanto, é a mesma coisa ! Criar Comment • Hora de criar a entidade Comment • Lembrete: esta entidade será associada a um Post Rake outra vez • Obs: Comment pertence a Post através da coluna post_id. • Convenção de Chave Estrangeira: <classe>_id Associações Usando associações • Criando formulário de Comment na tela de detalhe de um Post – /app/views/blog/show.rhtml Partials • “Don’t Repeat Yourself” (DRY) • Uma das maneiras de separar trechos de código • Toda partial começa com underline “_” – <%= render :partial => "comment", :collection => @post.comments %> • Associação has_many em Post automaticamente fornece um hash chamado comments (nome da outra entidade no plural) Action para Comment • <% form_for :comment, @comment, :url => {:action => 'add_comment', :id => @post } do |f| %> – Action esperada: add_comment – Passando parâmetros: params[:id] e params[:comment] – Hash params[:comment] contém todos os campos do formulário enviado. Resultado Final • Tela de Post com a lista de Comments Layouts • Todo novo controller automaticamente ganha um layout no diretório: – /app/views/layouts/<controller>.rhtml – As views desse controller preenchem o espaço: • <%= @content_for_layout %> Testes Unitários • Toda nova entidade ganha um arquivo para teste unitário em: – /app/test/unit/<entidade>_test.rb • Devemos seguir os preceitos de Test-Driven Development: – “Se não vale a pena testar, para que estamos codificando?” Ambiente de Teste • Os testes acontecem em banco de dados separado do desenvolvimento – <projeto>_test • Cada teste roda de maneira isolada: os dados modificados em um teste não afetam outro teste • Cada teste unitário tem um arquivo de “fixture”, carga de dados para testes: – /app/test/fixture/<tabela>.yml Fixture YAML • “YAML Ain’t a Markup Language” • Maneira de serializar objetos Ruby em forma de texto • Formato humanamente legível • Mais leve e simples que XML Rodando Testes Unitários • Todos os testes unitários – rake test:units • Apenas um teste unitário: – ruby test/unit/<entidade>_test.rb Testes Funcionais • Todo novo controller ganha uma classe de teste em: – /app/test/functional/<classe>_controller_test.rb • Devemos testar cada action do controller • Métodos como get e post simulam navegação com um browser Rodando Testes Funcionais • Todos os testes funcionais: – rake test:functionals • Apenas um testes funcional: – ruby test/functional/<classe>_controller_test.rb Mais Testes • Testes Unitários devem testar todos os aspectos da entidade como associações, validações, callbacks, etc • Testes Funcionais devem testar todas as actions de um mesmo controller, todos os fluxos, redirecionamentos, filtros, etc • Testes Integrados servem para avaliar a navegação e fluxos entre actions de diferentes controllers. Funcionam de maneira semelhante a um teste funcional Ajax • Rails é o melhor modelo de framework para Ajax • Ajax é codificado em Ruby puro • Integração com as bibliotecas Prototype e Script.aculo.us • Ajax representa um passo em direção a um “Aplicativo” Web – Sem necessidade de recarregar a página toda a cada ação – Capacidade de atualizar apenas trechos da tela – Capacidade de realizar um post (submit) sem sair da página – Capacidade de receber apenas a informação que precisa ser atualizada em vez de receber a página inteira View Ajaxfied • Maneira simples: apenas trocar form_for para remote_form_for Action Ajaxfied • request.xhr? checa se veio chamada via Ajax. Caso contrário redireciona para a mesma action de antes, que retorna a página toda • Desta vez guardamos o novo comment na variável de instância @comment Arma Secreta: RJS • Mesma convenção: action add_comment espera encontrar a página – /app/views/blog/add_comment.rjs Ativando Ajax • Ativado por controller, através de seu layout com o método javascript_include_tag Testando Ajax • Na foto de tela não podemos mostrar o efeito. • Recomendamos testar ao vivo. As possibilidades são enormes! Active Record Interativo • script/console • Toda entidade criada pode ser manipulada pelo console • Facilita testes antes de criar as actions Produto Final • Mini Blog criado conforme requerimentos iniciais (slide 9) • Plus: pequeno brinde via Ajax • Conseguimos criar entidades e tabelas sem mapear campo-a-campo manualmente – deixe o computador trabalhar por nós • Infraestrutura completa de testes unitários, funcionais e integrados • Obs: este é um aplicativo de demonstração, muito mais ainda pode ser feito ! O que NÃO fizemos • Não precisamos recompilar e reinstalar o aplicativo a cada mudança • Não precisamos reiniciar o servidor a cada mudança • Não precisamos mapear cada uma das colunas das tabelas para as entidades • Não precisamos configurar dezenas de arquivos XML. Basicamente colocamos a senha do banco de dados, apenas • Não precisamos usar Javascript para fazer Ajax: a maior parte pode ser feita com Ruby puro • Não sentimos falta de taglibs: expressões Ruby, partials foram simples o suficiente • Não precisamos codificar código-cola, o framework possui “padrões espertos” afinal, todo aplicativo Web tem a mesma infraestrutura Linhas de Código • Estatística polêmica mas relevante • Ruby on Rails permite fazer muito mais com muito menos Próximos Passos • Aprender mais! – Programming Ruby (livro gratuito! Em inglês) – http://www.rubycentral.com/book/intro.html – Agile Web Development With Rails (livro mais famoso de Rails, em inglês) – http://www.pragmaticprogrammer.com/titles/rails2/ – Melhores websites sobre Ruby e Rails – http://del.icio.us/fabioakita/rubyonrails – Akita On Rails: principal site de Rails do Brasil – http://www.akitaonrails.com … e TAMBÉM • Repensando a Web com Rails – Primeiro livro de Ruby on Rails em português no Brasil – Documentação completa do Rails versão 1.1.2 – Cada um dos tópicos desta demonstração em detalhes – Por Fabio Akita (www.balanceonrails.com.br) • Consultor SAP há 5 anos • Gerente de Projetos PMP • Desenvolvedor Java há 8 anos • Utilizando diversas plataformas de desenvolvimento há 14 anos – Pela editora Brasport, já disponível! Dúvidas Sugestões Críticas • Participe de nosso grupo – [email protected] • Podem me escrever diretamente – [email protected]