ruby on rails regis

64
Ruby on Rails Regis Pires Magalhães [email protected] http://regispiresmag.googlepages.com Última atualização em 24/01/2007

Upload: elliando-dias

Post on 12-Nov-2014

2.287 views

Category:

Technology


3 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Ruby On Rails Regis

Ruby on Rails

Regis Pires Magalhã[email protected]

http://regispiresmag.googlepages.comÚltima atualização em 24/01/2007

Page 2: Ruby On Rails Regis

Instalação do Ruby

1 – No Linux - http://rubyforge.org/frs/download.php/7858/ruby-1.8.4.tar.gz

tar xvzf ruby-<versão>.tgz./configuremakemake install

2 – No Windows - One-Click Installer – já vem com RubyGems:http://rubyforge.org/frs/download.php/11488/ruby184-20.exe

Page 3: Ruby On Rails Regis

Instalação do RubyGems

• Desnecessário no Windows, pois já vem no One-Click Installer• RubyGems - gerenciador de pacotes do Ruby

1 – Descompactar: http://rubyforge.org/frs/download.php/11290/rubygems-0.9.0.zip

2 – Executar: ruby setup.rb

Page 4: Ruby On Rails Regis

Instalação do Rails

• Via Internet:gem install rails --include-dependencies

• Local:– Ir para diretório onde estão os arquivos gem e executar: gem install activesupport actionpack actionmailer activerecord actionwebservice rails –-local

– Arquivos necessários:• rails-1.1.6.gem• actionmailer-1.2.5.gem• actionpack-1.12.5.gem• actionwebservice-1.1.6.gem• activerecord-1.14.4.gem• activesupport-1.3.1.gem

Page 5: Ruby On Rails Regis

Instalação do PostgreSQL

• No Windows:– Descompactar:

• postgresql-8.1.4-1.zip– Executar:

• postgresql-8.1.msi

Page 6: Ruby On Rails Regis

Instalação da biblioteca do PostgreSQL para o Ruby

• Via internet:gem install postgres-pr

• Local:gem install postgres-pr –-local

Page 7: Ruby On Rails Regis

Criação do Banco de Dados

create database <projeto>_<ambiente>

create database livraria_development

Ambientes:• Development - desenvolvimento• Test - testes• Production - produção

Page 8: Ruby On Rails Regis

Criação de tabelas

• usuarios– id serial (PK)– nome varchar(75)– email varchar(75)– senha varchar(10)– admin int4 – img bytea

• tipos– id serial (PK)– descricao varchar(50)

• categorias– id serial (PK)– descricao varchar(50)

• produtos– id serial (PK)– descricao varchar(100)– tipo_id int4– categoria_id int4

• telefones– id serial (PK)– usuario_id int4– numero varchar(10)

Page 9: Ruby On Rails Regis

Criação do Projeto

rails <projeto>

>rails livrariacreatecreate app/controllerscreate app/helperscreate app/modelscreate app/views/layoutscreate config/environmentscreate componentscreate dbcreate doccreate libcreate lib/taskscreate log...

Page 10: Ruby On Rails Regis

Configuração do acessoa banco de dados

• Abrir arquivo config/database.yml:development: adapter: postgresqldatabase: livraria_developmentusername: postgrespassword: 1234host: localhost

...

Page 11: Ruby On Rails Regis

Testando o Servidor WEB

ruby script/server

ruby script/server –e [development|test|production]

• Development é o default.

Page 12: Ruby On Rails Regis

Geração de um Scaffold

• Scaffold - tradução: andaime, palanque, armação , esqueleto• Scaffold é um meio de criar código para um determinado modelo

através de um determinado controlador.• É um meio de começarmos rapidamente a ver os resultados no

navegador Web e um método muito rápido de implementar o CRUD (Create, Retrieve, Update, Delete) na sua aplicação.

ruby script/generate scaffold <Model> <Controller>

ruby script/generate scaffold Usuario Admin::Usuario

• O controlador Admin::Usuario gerenciará as ações recebidas. O rails irá criar a seguinte estrutura de diretórios: <aplicação>/controllers/admin

Page 13: Ruby On Rails Regis

Outras gerações comuns

• Modelo:ruby script/generate model <Model>

• Controlador:ruby script/generate controller <controller>

Page 14: Ruby On Rails Regis

Diretórios da aplicação• controllers

– Classes de controle.– Uma classe controller trata uma requisição Web do usuário.– A URL da requisição Web é mapeada para uma classe de controle e

para um método dentro da classe.• views

– Armazena as templates de visualização para preenchimento com dados da aplicação, conversão para HTML e retorno para o browser.

• models– Armazena as classes que modelam e encapsulam dos dados

armazenados nos bancos de dados da aplicação.• helpers

– Armazena classes de auxílio usadas para ajudar as classes model, view e controller. Ajudam a manter os códigos de model, view e controller bastante enxutos.

Page 15: Ruby On Rails Regis

Modelo<aplicação>/app/models/usuario.rb:

class Usuario < ActiveRecord::Baseend

• A classe Usuario 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.

• Nome de tabela diferente da convenção:

class EncomendaCliente < ActiveRecord::Baseset_table_name "encomendas_clientes"

end

Page 16: Ruby On Rails Regis

Modelo• 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 (Usuario), a tabela tem o nome do plural (usuarios).

• Convenção: Toda tabela tem uma chave primária chamada id que é de tipo auto-incremento.

Page 17: Ruby On Rails Regis

Active Record Interativo

ruby script/console• Toda entidade criada pode ser manipulada

pelo console.• Facilita testes antes de criar as actions.

Page 18: Ruby On Rails Regis

Acrescentando validaçãoclass Usuario < ActiveRecord::Base validates_presence_of :nome validates_length_of :nome, :maximum => 75, :message => "Máximo de %d caracteres."end

Outros exemplos: validates_uniqueness_of :cpf validates_length_of :cpf, :is => 11 validates_length_of :user_name, :within => 6..20, :too_long => "deve ser menor", :too_short => "deve ser maior" validates_length_of :first_name, :maximum=>30

Page 19: Ruby On Rails Regis

Controller

• 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• Uma classe Controller pode ter quantas Actions quanto

necessárias.class Admin::UsuarioController < ApllicationControllerdef index

render :text => “Hello World!”end

end

Page 20: Ruby On Rails Regis

Acessando uma Action

• Roteamento Customizável (routes.rb)http://localhost:3000/:controller/:action/:id

• Exemplo:http://localhost:3000/blog/index

• blog = app/controller/blog_controller.rb• index = método index em BlogController

Page 21: Ruby On Rails Regis

View

index.rhtml:<h3>Hello da View!</h3>

blog_controller.rb:

Page 22: Ruby On Rails Regis

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.

Page 23: Ruby On Rails Regis

Modificando a listagem

/app/views/admin/usuario/list.rhtml

• Podemos alterar o layout ou qualquer código como quisermos.

Page 24: Ruby On Rails Regis

Layouts

• Layouts permitem o compartilhamento de conteúdo.• 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 %>

Page 25: Ruby On Rails Regis

Layouts# test_controller.rbclass TestController < ApplicationController

layout "default"def indexend

end<!-- default.rhtml --><html><head>

<title>Teste</title></head><body>

<h1>Layout Padrao</h1><%= @content_for_layout %>

</body></html>

Page 26: Ruby On Rails Regis

Scriptlets

<% @usuarios.each do |usuario| %>Faz alguma coisa com usuario<% end %>...<% if number == "7" %>Está correto!<% end %>

Page 27: Ruby On Rails Regis

Flash• flash[:notice] está disponível somente

naquela requisição. Usado para comunicação entre ações: passagem de string contendo informação ou erro.

• Similar a variáveis de sessão, mas somente existe de uma página para outra. Uma vez que a requisição para a qual foram propagadas acaba, elas são automaticamente removidas do contexto de execução.def three flash[:notice] => "Hello" flash[:warning] => "Mewl" flash[:error] => "Erro!" renderend

Page 28: Ruby On Rails Regis

Logger• Nível de log configurado em:

config/environment.rb:config.log_level = :debug

• Mensagens escritas em um arquivo no diretório log. O arquivo de log usado depende do ambiente (environment) usado pela aplicação. Ex.: log/development.loglogger.warn("I don't think that's a good idea" )logger.info("Dave's trying to do something bad" )logger.error("Now he's gone and broken it" )logger.fatal("I give up" )

Page 29: Ruby On Rails Regis

class PersonController < ApplicationController model :person paginate :people, :order => 'last_name, first_name', :per_page => 20 # ...end

Paginação

• Para todas as ações do Controller:

Page 30: Ruby On Rails Regis

Paginação

• Para uma única ação do Controller: def list @person_pages, @people = paginate :people, :order => 'last_name, first_name' end

Page 31: Ruby On Rails Regis

Paginação

• Condicional@upcoming_event_pages, @upcoming_events = paginate :upcoming_event, :conditions => "event LIKE '%"params['upcoming_event']['search'].to_s"%'", :order_by => "date DESC", :per_page => 10

Page 32: Ruby On Rails Regis

Paginação

• Genérica def list @person_pages = Paginator.new self, Person.count, 10,

params[:page] @people = Person.find :all, :order => 'last_name, first_name', :limit => @person_pages.items_per_page, :offset => @person_pages.current.offset end

Page 33: Ruby On Rails Regis

Paginação• paginate(collection_id, options={}) – Retorna um paginator e

uma coleção de instâncias de modelo Active Record para a página atual.

• Opções: – :singular_name: the singular name to use, if it can‘t be inferred by singularizing the

collection name – :class_name: the class name to use, if it can‘t be inferred by camelizing the singular

name – :per_page: the maximum number of items to include in a single page. Defaults to 10 – :conditions: optional conditions passed to Model.find(:all, *params) and Model.count – :order: optional order parameter passed to Model.find(:all, *params) – :order_by: (deprecated, used :order) optional order parameter passed to

Model.find(:all, *params) – :joins: optional joins parameter passed to Model.find(:all, *params) and Model.count – :join: (deprecated, used :joins or :include) optional join parameter passed to

Model.find(:all, *params) and Model.count – :include: optional eager loading parameter passed to Model.find(:all, *params) and

Model.count – :select: :select parameter passed to Model.find(:all, *params) – :count: parameter passed as :select option to Model.count(*params)

Page 34: Ruby On Rails Regis

Paginação• Em um array / collection:

def paginate_collection(collection, options = {}) default_options = {:per_page => 10, :page => 1} options = default_options.merge options pages = Paginator.new self, collection.size, options[:per_page], options[:page] first = pages.current.offset last = [first + options[:per_page], collection.size].min slice = collection[first...last] return [pages, slice] end

@pages, @users = paginate_collection User.find_custom_query, :page => @params[:page]

Page 35: Ruby On Rails Regis

Convenção de Nomes

Page 36: Ruby On Rails Regis

Fluxo do MVC

Page 37: Ruby On Rails Regis

Parâmetros de Forms

Page 38: Ruby On Rails Regis

Associações• Todo usuario pode ter vários telefones.• Telefone pertence a Usuario através da coluna usuario_id.• Convenção de Chave Estrangeira: <classe>_idclass Usuario < ActiveRecord::Base has_many :telefones # um usuário tem muitos telefones validates_presence_of :nome validates_length_of :nome, :maximum => 75, :message => "Máximo de %d caracteres."end

class Telefone < ActiveRecord::Base belongs_to :usuario # um telefone pertence a um usuárioend

Page 39: Ruby On Rails Regis

Associações

• Um para Um

Page 40: Ruby On Rails Regis

Associações

• Um para Muitos

Page 41: Ruby On Rails Regis

Associações

• Muitos para Muitos

Page 42: Ruby On Rails Regis

Mapeamento de Tipos

Page 43: Ruby On Rails Regis

Rake

• Programa em Ruby para realizar um conjunto de tarefas (tasks).

• Cada tarefa tem um nome, uma lista de tarefas das quais ela depende e uma lista de ações a realizar.

• Para ver as tarefas existentes em um arquivo rake (Rakefile):rake --tasks

Page 44: Ruby On Rails Regis

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?”

• 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

• Executando todos os testes unitáriosrake test:units

• Executando apenas um teste unitário:ruby test/unit/<entidade>_test.rb

Page 45: Ruby On Rails Regis

Testes Unitáriosrequire File.dirname(__FILE__) + '/../test_helper'class PostTest < Test::Unit::TestCase fixtures :posts # Replace this with your real tests. def test_add_comment # adiciona um post @post = Post.create(:title => 'New Post', :body => 'New Post', :author => 'Anonymous') # adiciona um comment @comment = @post.comments.create(:body => 'New Comment', :author => 'Anonymous') assert_not_equal nil, @comment # recarrega a entidade @post.reload # checa se existe apenas um post assert_equal 3, Post.count # já existem 2 posts na fixture # checa se esse post tem apenas um comment assert_equal 1, @post.comments.count endend

Page 46: Ruby On Rails Regis

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

Page 47: Ruby On Rails Regis

Fixture YAML# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.htmlronaldo: id: 1 name: Ronaldo login: ronaldo admin: true email: [email protected] data: 2004-07-01 00:00:00 hashed_password: <%= Digest::SHA1.hexdigest('abracadabra') %>marcus: id: 2 name: Marcus login: marcus admin: false email: [email protected] data: <%= 1.day.from_now.strftime("%Y-%m-%d") %> hashed_password: <%= Digest::SHA1.hexdigest('teste') %>

Page 48: Ruby On Rails Regis

Fixture YAML

Page 49: Ruby On Rails Regis

Fixture YAML

Page 50: Ruby On Rails Regis

Testes Unitários

Page 51: Ruby On Rails Regis

Testes Unitários

Page 52: Ruby On Rails Regis

Testes Unitários

Page 53: Ruby On Rails Regis

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• Executando todos os testes funcionais:

rake test:functionals• Executando apenas um testes funcional:

ruby test/functional/<classe>_controller_test.rb

Page 54: Ruby On Rails Regis

Testes Funcionaisrequire File.dirname(__FILE__) + '/../test_helper'require 'blog_controller'

# Re-raise errors caught by the controller.class BlogController; def rescue_action(e) raise e end; end

class BlogControllerTest < Test::Unit::TestCase fixtures :posts

def setup @controller = BlogController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end

def test_create num_posts = Post.count # checa total de posts atual # simula submit do formulário de criar novo post post :create, :post => {:title => 'New Title', :body => 'New Post', :author => 'Anonymous'} # checa se depois da action fomos redirecionados assert_response :redirect # checa se realmente foi acrescentado um novo post assert_equal num_posts + 1, Post.count endend

Page 55: Ruby On Rails Regis

Testes Funcionaisrequire File.dirname(__FILE__) + '/../test_helper'require 'users_controller'

# Re-raise errors caught by the controller.class UsersController; def rescue_action(e) raise e end; end

class UsersControllerTest < Test::Unit::TestCase fixtures :users def setup @controller = UsersController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new end

def test_index get :index assert_redirected_to :controller => "login", :action => "login" end def test_index_with_login @request.session[:user] = users(:ronaldo).id get :index assert_response :success assert_tag :tag => "table", :children => { :count => User.count + 1, :only => { :tag => "tr" } } assert_tag :tag => "td", :content => users(:ronaldo).name endend

Page 56: Ruby On Rails Regis

Testes Funcionais

Page 57: Ruby On Rails Regis

Testes Funcionais

Page 58: Ruby On Rails Regis

Testes de Integração

• Para gerar o teste:script/generate integration_test login

• Para executar o teste:rake test:integration

Page 59: Ruby On Rails Regis

Testes de Integraçãorequire "#{File.dirname(__FILE__)}/../test_helper"class LoginTest < ActionController::IntegrationTest fixtures :users def test_login user = users(:ronaldo) get "/home" assert_redirected_to "/login/login" follow_redirect! assert_response :success post "/login/login" assert_response :success assert_equal "Invalid login and/or password.", flash[:notice] post "/login/login", :login => user.login, :password => user.password assert_redirected_to "/home" follow_redirect! assert_tag :tag => "div", :attributes => { :id => "edit_form" } endend

Page 60: Ruby On Rails Regis

Teste de Performance

Page 61: Ruby On Rails Regis

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

Page 62: Ruby On Rails Regis

Helpers

# Global helper para views.module ApplicationHelper # Formata um float com duas casa decimais def fmt_decimal(valor, decimais) sprintf("%0.#{decimais}f", valor) endend

Page 63: Ruby On Rails Regis

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.

Page 64: Ruby On Rails Regis

Referências• Agile Web Development with Rails. 2ª Edição.

– Thomas e David Heinemeier Hansson. • Entendendo Rails

– Fábio Akita (http://www.esnips.com/web/BalanceOnRails)• Creating a weblog in 15 minutes

– http://media.rubyonrails.org/video/rails_take2_with_sound.mov• Tutorial de Rails do TaQ

– http://www.eustaquiorangel.com/downloads/tutorialrails.pdf• Tutorial de Ruby on Rails do Ronaldo Ferraz

– http://kb.reflectivesurface.com/br/tutoriais/rubyOnRails• Rolling with Ruby on Rails by Curt Hibbs

– http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html• Tutorial de Ruby do TaQ

– http://www.eustaquiorangel.com/downloads/tutorialruby.pdf