Ruby on Rails 2.2 O QUE HÁ DE NOVO? Primeira Edição



Documentos relacionados
Omega Tecnologia Manual Omega Hosting

Desenvolvendo Websites com PHP

Finalizando o Pedido (Tarefa G) Prof. Fellipe Aleixo (fellipe.aleixo@ifrn.edu.br)

4 O Workflow e a Máquina de Regras

SUMÁRIO 1. AULA 6 ENDEREÇAMENTO IP:... 2

Configurando o IIS no Server 2003

Programação Orientada a Objetos com PHP & MySQL Cookies e Sessões. Prof. MSc. Hugo Souza

Procedimentos para Reinstalação do Sisloc

Scriptlets e Formulários

WF Processos. Manual de Instruções

Operações de Caixa. Versão 2.0. Manual destinado à implantadores, técnicos do suporte e usuários finais

INTRODUÇÃO À TECNOLOGIA SERVLETS

Parte I. Demoiselle Mail


Instalando servidor Apache com MySQL e as linguagens ColdFusion e PHP. XAMPP (xampp-win installer.exe), veja aqui.

Entendendo como funciona o NAT

PHP: Formulários e upload de múltiplos arquivos Por Alfred Reinold Baudisch 28 de fevereiro de 2006.

Revisão: Introdução. - Integração com o AutoManager; 1 Atualização de versão do banco de dados PostgreSQL

Trecho retirando do Manual do esocial Versão 1.1

Dicas para usar melhor o Word 2007

DOCUMENTAÇÃO DO FRAMEWORK - versão 2.0

Introdução a Banco de Dados

TUTORIAL: MANTENDO O BANCO DE DADOS DE SEU SITE DENTRO DO DOMÍNIO DA USP USANDO O SSH!

Vamos criar uma nova Página chamada Serviços. Clique em Adicionar Nova.

Exibindo o Catálogo (Tarefa C) Prof. Fellipe Aleixo (fellipe.aleixo@ifrn.edu.br)

Como atualizar os preços da ABCFarma.

Programando em PHP. Conceitos Básicos

Instalando o WordPress em localhost

Mais sobre uso de formulários Site sem Ajax

Orientação a Objetos

Follow-Up Acompanhamento Eletrônico de Processos (versão 3.0) Manual do Sistema. 1. Como acessar o sistema Requisitos mínimos e compatibilidade

O sistema está pedindo que eu faça meu login novamente e diz que minha sessão expirou. O que isso significa?

2 echo "PHP e outros.";

Transações Seguras em Bancos de Dados (MySQL)

Manual de configuração do sistema

No Fedora, instalamos os pacotes "mysql" e "mysql-server", usando o yum:

Manual de Administração DPS Printer 2.1 NDDigital S/A - Software

RESTAURAÇÃO NO WINDOWS 8

Listando itens em ComboBox e gravando os dados no Banco de Dados MySQL.

P S I 2. º A N O F 5 M E S T R E / D E T A L H E E P E S Q U I S A. Criar uma relação mestre-detalhe. Pesquisa de informação

02 - Usando o SiteMaster - Informações importantes

Manual das funcionalidades Webmail AASP

Inserindo Dados no Banco de Dados Paradox.

Manual Captura S_Line

Cartilha. Correio eletrônico

CRIANDO UM BANCO DE DADOS

Manual Operacional SIGA

MANUAL DE UTILIZAÇÃO SISTEMA DE CADASTRO INTRANET

Validando dados de páginas WEB

PHP Material de aula prof. Toninho (8º Ano)

Instalando software MÉDICO Online no servidor

Gravando uma Áudio Conferência

Satélite. Manual de instalação e configuração. CENPECT Informática cenpect@cenpect.com.br

Tutorial do administrador do HelpCenterLive (Sistema de Ajuda)

OCOMON PRIMEIROS PASSOS

Como acessar o novo webmail da Educação? Manual do Usuário. 15/9/2009 Gerencia de Suporte, Redes e Novas Tecnologias Claudia M.S.

3. No painel da direita, dê um clique com o botão direito do mouse em qualquer espaço livre (área em branco).

Inventario de produtos

SSE 3.0 Guia Rápido Parametrizando o SISTEMA DE SECRETARIA Nesta Edição Configurando a Conexão com o Banco de Dados

mkdir /srv/www/default/html/calculadora/imagens mkdir /srv/www/default/html/calculadora/blocos

Manual do Almoxarifado SIGA-ADM

Operador de Computador. Informática Básica

MANUAL COTAÇAO WEB MANUAL MANUAL AVANÇO INFORMÁTICA AVANÇO INFORMÁTICA. [Digite seu endereço] [Digite seu telefone] [Digite seu endereço de ]

Resolvendo problemas de conexão de rede wireless no pregão 83/2008

Microsoft Access XP Módulo Um

Bem- Vindo ao manual de instruções do ECO Editor de COnteúdo.

PASSO A PASSO PARA CADASTRAR OFERTAS, PRODUTOS E SERVIÇOS

PHP (Seções, Cookies e Banco de Dados)

MANUAL DO ANIMAIL Terti Software

Comm5 Tecnologia Protocolo MI. Protocolo. Família MI

Arquitetura de Rede de Computadores

Tutorial do módulo Carteira Nacional de Militante

QUALIDATA Soluções em Informática. Módulo CIEE com convênio empresas

DNS DOMAIN NAME SERVER

CRIANDO BANCOS DE DADOS NO SQL SERVER 2008 R2 COM O SQL SERVER MANAGEMENT STUDIO

1- Requisitos mínimos. 2- Instalando o Acesso Full. 3- Iniciando o Acesso Full pela primeira vez

MANUAL WEBMAIL HORDE-V.01 IBILCE/UNESP

8VDQGR5HSRUW0DQDJHUFRP&ODULRQH3RVWJUH64/ -XOLR&HVDU3HGURVR 8VDQGRSDUkPHWURV

CONSTRUÇÃO DE BLOG COM O BLOGGER

Manual do sistema SMARsa Web

Despachante Express - Software para o despachante documentalista veicular DESPACHANTE EXPRESS MANUAL DO USUÁRIO VERSÃO 1.1

Procedimentos para Instalação do Sisloc

MANUAL TISS Versão

Aula 01 - Formatações prontas e condicionais. Aula 01 - Formatações prontas e condicionais. Sumário. Formatar como Tabela

Na Figura a seguir apresento um exemplo de uma "mini-tabela" de roteamento:

Tutorial - Monitorando a Temperatura de Servidores Windows

Novell. Novell Teaming 1.0. novdocx (pt-br) 6 April 2007 EXPLORAR O PORTLET BEM-VINDO DESCUBRA SEU CAMINHO USANDO O NOVELL TEAMING NAVIGATOR

AULA APLICAÇÕES PARA WEB SESSÕES E LOGIN E SENHA

INSTALANDO E CONFIGURANDO O MY SQL

Daruma NFCe Conheça todos os passos para testar a NFCe Daruma

Web Design Aula 11: Site na Web

15/8/2007 Gerencia de Tecnologia da Informação Claudia M.S. Tomaz

UNIVERSIDADE FEDERAL DO RIO GRANDE DO NORTE ESCOLA AGRÍCOLA DE JUNDIAÍ EAJ - PRONATEC / REDE etec MÓDULO III DESENVOLVIMENTO PROFESSOR ADDSON COSTA

Programação Orientada a Objetos com PHP & MySQL Sistema Gerenciador de Banco de Dados: Introdução e configuração de bases de dados com Postgre e MySQL

- Versão 1.0 Página 1

1 REQUISITOS BÁSICOS PARA INSTALAR O SMS PC REMOTO

1. Instalei o DutotecCAD normalmente no meu computador mas o ícone de inicialização do DutotecCAD não aparece.

NetEye Guia de Instalação

Transcrição:

Ruby on Rails 2.2 O QUE HÁ DE NOVO? Primeira Edição

Ruby on Rails 2.2 O QUE HÁ DE NOVO? Primeira Edição por Carlos Brando traduzido por Carl Youngblood

Copyright 2008 Carlos Brando. Todos os direitos reservados. Primeira Edição: Outubro 2008 Carlos Brando http://www.nomedojogo.com Carl Youngblood http://blog.youngbloods.org

Ruby on Rails 2.2 INTRODUÇÃO O Ruby on Rails 2.2 está cheio de novidades, incluindo novas funcionalidades, melhorias e correções de bugs antigos. Neste livro você encontrará uma breve descrição, acompanhada de um exemplo (na maioria dos casos) de cada uma das principais novidades deste versão. Escrever este livro foi um trabalho árduo, por isto espero que ele lhe seja muito útil, ajudando-o a usar mais plenamente cada novo recurso incluído no Ruby on Rails. À partir desta versão o Rails passa a ser políglota. Fazo uso do novo sistema de internacionalização (i18n) podemos construir aplicativos para usuários do mundo com pouquíssimo esforço. Muito trabalho foi feito para deixar o Rails thread-safety e o mais preparado possível para o futuro Ruby 1.9. Também houve uma preocupação grande para deixá-lo mais compatível com o JRuby. Embora o recurso de thread-safe ainda não esteja disponível para todos nós, já que ele apenas funcionará em máquinas virtuais com suporte a threads nativas, como o JRuby por exemplo, ele é uma grande adição ao framework. Se no passado houve muita reclamação quanto a documentação do Rails, agora ninguém poderá mais reclamar. Um grande trabalho foi feito para documentar o código e as funcionalidades do Rails. Quer um exemplo? Execute no terminal: rake doc:guides Esta tarefa criará uma pasta doc/guides na raiz do seu projeto com vários guias para auxiliá-lo durante o aprizado do Rails. 7

Ruby on Rails 2.2 - O que há de novo? Capitulo 1 ActiveRecord NOVA OPÇÃO PARA ASSOCIAÇÕES: :VALIDATE Uma nova opção foi acrescentado às associações do Rails. A opção validação de objetos associados ao modelo. Veja um exemplo: :validate class AuditLog < ActiveRecord::Base belongs_to :developer, :validate => false log = AuditLog.create(:developer_id => 0, :message => "") log.developer = Developer.new puts log.developer.valid? # => false 8 pode ser usada para ligar ou desligar a

Capitulo 1: ActiveRecord puts log.valid? # => true puts log.save # => true Como você pode ver no exemplo acima, embora o objeto associado ( Developer) não seja válido, ainda assim o objeto principal (AuditLog) foi salvo no banco de dados. Este não era o comportamento normal nas versões anteriores do Rails, onde um objeto pai só poderia ser gravado se todos os filhos fossem válidos. Embora no exemplo acima estamos desligando a validação de associações, para demostrar o novo recurso, este é o novo valor padrão para este tipo de relacionamento de agora em diante. Ou seja, todas as validações em associações belongs_to estarão desligadas (como no exemplo) e para habilitarmos o comportamento antigo devemos usar a expressão :validate => true. UMA NOVA FORMA DE ESPECIFICAR CONDITIONS USANDO HASH Ao realizar buscas no banco de dados, por vezes temos de fazer uso da opção :joins a fim de melhorar a performance de nosso aplicativo, em outros casos precisamos simplesmente recuperar algum tipo de informação que depe do resultado de duas tabelas. Por exemplo, se desejássemos recuperar todos os usuários do sistema que compraram itens da cor vermelha, faríamos algo assim: User.all :joins => :items, :conditions => ["items.color =?", 'red'] Este tipo de sintaxe parece incomodar já que você precisa incluir o nome da tabela (no caso items) dentro de uma string. O código parece estranho. 9

Ruby on Rails 2.2 - O que há de novo? No Rails 2.2 encontraremos uma novidade nesta questão, nos permitindo fazer a mesma coisa de uma forma um pouco diferente, usando uma chave dentro do Hash para identificar a tabela: User.all :joins => :items, :conditions => { :age => 10, :items => { :color => 'red' } } # um outro exemplo que talvez deixe o código mais claro User.all :joins => :items, :conditions => { :users => { :age => 10 }, :items => { :color => 'red' } } Na minha opinião, desta forma o código fica muito mais claro, principalmente se temos de condicionar muitos campos de várias tabelas. Só tenha em mente que a chave usada é o nome da tabela (você percebe pelo nome pluralizado) ou um alias caso você o tenha especificado na query. NOVA OPÇÃO :FROM PARA MÉTODOS DE CÁLCULO DO ACTIVERECORD Uma nova opção foi incluída aos métodos de cálculos do ActiveRecord (count, sum, average, minimum e maximum). Ao fazer uso da opção :from, podemos sobrecarregar o nome da tabela na query gerada pelo ActiveRecord, o que não parece muito útil em um primeiro momento. Mas algo interessante que esta opção nos permite fazer é forçar o MySQL a usar um índice especifico ao realizar o cálculo desejado. Veja alguns exemplos de uso: 10

Capitulo 1: ActiveRecord # Forçando o MySQL a usar um índice para realizar o cálculo Edge.count :all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5') # Realizando o cálculo em uma tabela diferente da classe associada Company.count :all, :from => 'accounts' MÉTODO MERGE_CONDITIONS DO ACTIVERECORD AGORA É PÚBLICO O método merge_conditions do ActiveRecord agora é um método público, o que significa que ele estará presente em todas os seus modelos. Este método faz exatamente o que o nome diz. Você pode informar várias e ele junta tudo em uma condition só. Por exemplo: conditions separadas em seus parâmetros class Post < ActiveRecord::Base a = { :author => 'Carlos Brando' } b = [ 'title =?', 'Edge Rails' ] Post.merge_conditions(a, b) # => "(\"posts\".\"author\" = 'Carlos Brando') AND (title = 'Edge Rails')" Note que ele une as conditions com um AND, sempre. 11

Ruby on Rails 2.2 - O que há de novo? DEFININDO COMO O MÉTODO VALIDATES_LENGTH_OF DEVE FUNCIONAR O método validates_length_of faz parte dos muitos métodos de validação contidos no ActiveRecord. Este método em particular serve para garantir que o valor gravado em uma determinada coluna no banco de dados terá um tamanho máximo, mínimo, exato, ou até mesmo se está em um intervalo de valores. Mas o termo "tamanho" é relativo. Hoje quando dizemos "tamanho" estamos nos referindo a quantidade de caracteres no texto. Mas imagine um caso onde eu tenha um campo em um formulário onde a limitação não seja definida pela quantidade de caracteres e sim pela quantidade de palavras, algo como "escreva um texto com no mínimo 100 palavras". Imagine uma página onde o usuário tenha de redigir uma redação, por exemplo. Hoje, para validar isto não teríamos outra escolha senão criarmos um novo método que faça esta validação. Mas à partir do Rails 2.2 poderemos personalizar o método validates_length_of para funcionar da forma como desejamos usando a opção :tokenizer. Veja um exemplo que resolveria o problema citado acima: validates_length_of :essay, :minimum => 100, :too_short => "Sua redação deve ter no mínimo %d palavras."), :tokenizer => lambda { str str.scan(/\w+/) } Este é apenas um exemplo do que podemos fazer com esta nova opção. Além disso podemos usa-lá para contar apenas a quantidade de dígitos, menções de uma única palavra, etc.. 12

Capitulo 1: ActiveRecord TRATANDO A OPÇÃO :LIMIT COMO BYTES À partir desta versão do Rails quando usarmos a opção :limit para colunas com números inteiros, em nossas migrations, estaremos nos referindo ao número de bytes, no MySQL e no PostgreSQL (no sqlite sempre foi assim). O tipo da coluna no banco de dados deperá da quantidade de bytes especifica. Veja o trecho de código que identifica o tipo da coluna para o MySQL: when when when when when else 1; 'tinyint' 2; 'smallint' 3; 'mediumint' nil, 4, 11; 'int(11)' # compatibility with MySQL default 5..8; 'bigint' raise(activerecorderror, "No integer type has byte size #{limit}") E para o PostgreSQL: when 1..2; 'smallint' when 3..4, nil; 'integer' when 5..8; 'bigint' INFORMANDO OUTRO PRIMARY_KEY EM ASSOCIAÇÕES Uma nova opção foi acrescentado aos métodos has_many e has_one: a opção :primary_key. Fazo uso desta opção podemos definir qual método do modelo associado retornará a chave primária que será usada na associação. Obviamente o método padrão é o id. Veja um exemplo de uso: 13

Ruby on Rails 2.2 - O que há de novo? has_many :clients_using_primary_key, :class_name => 'Client', :primary_key => 'name', :foreign_key => 'firm_name' O método has_one funciona exatamente como no exemplo acima. NOVO HELPER PARA TESTES (ASSERT_SQL) Talvez você já conheça o método assert_queries que ajuda a validar nos testes a quantidade de queries executadas. Por exemplo: assert_queries(firm.partial_updates?? 0 : 1) { firm.save! } No teste acima estou afirmando que se houver caso contrário nenhuma deve ser executada. partial_updates uma query deve ser executada no banco de dados, Agora ganhamos mais um helper para ajudar a testar o tipo de query executada, o método assert_sql. Um exemplo: def test_empty_with_counter_sql company = Firm.find(:first) assert_sql /COUNT/i do assert_equal false, company.clients.empty? No exemplo acima estou confirmando que no bloco informado ao método pelo menos uma query deve conter a palavra COUNT. Obviamente você pode ser mais especifico na expressão regular que estiver usando. Vamos pegar um outro exemplo: 14

Capitulo 1: ActiveRecord assert_sql(/\(\"companies\".\"id\" IN \(1\)\)/) do Account.find(1, :include => :firm) MIGRATIONPROXY Imagine que ao rodar uma série de migrations um determinado modelo seja renomeado. Agora imagine que antes disto acontecer uma outra migration faça referencia a este modelo. Isto causará um erro feio e parará a execução de suas migrations. Para evitar este tipo de problema foi criado uma nova classe chamada MigrationProxy que armazena o nome, a versão e o nome do arquivo de cada migration e usa estas informações para carregar a migration somente quando ela for necessária, evitando carregar todas elas de uma vez. POOL DE CONEXÕES NO RAILS Algo que muita gente reclama sobre o Rails é que ele é lento. Sabemos que isto não é totalmente verdade, mas também sabemos que muita coisa pode ser feita para melhorar a performance dele. Uma destas coisas acabou de se feita. Foi incluído ao Rails um Pool de Conexões com o banco de dados. Toda vez que uma requisição ao banco de dados é feita, perde-se algum tempo criando uma nova conexão e só depois é que a pesquisa ou gravação é realizada. Olhando superficialmente pode parecer algo muito rápido e simples, mas abrir uma conexão com o banco de dados não é tão simples assim. É necessário estabelecer uma conexão física com o servidor do banco, autenticar a conexão e realizar mais uma série de validações. Tudo isto consome recursos e tempo. Após criar esta conexão, o Rails a usa para todas as requisições necessárias, e queries mais pesadas podem atrasar a 15

Ruby on Rails 2.2 - O que há de novo? execução de outras requisições. Isto explica muito bem o porque de o banco de dados se tornar o vilão de alguns grandes projetos criados em Rails. A solução para este tipo de problema é criar um pool de conexões com o banco de dados e distribuir as requisições feitas entre estas conexões. O processo é o seguinte: Uma conexão com o banco de dados é aberta e utilizada para realizar uma pesquisa. Depois disso, ao invés de fecha-la, ela é armazena no pool de conexões. Quando uma outra requisição é feita, ao invés de abrir uma nova conexão, o sistema reaproveita uma que já foi aberta, diminuindo o tempo e os recursos necessários para realizar a tarefa. Várias conexões podem ser armazenadas no pool ao mesmo tempo e as requisições serão distribuídas entre elas. Isto significa que mesmo com uma querie lenta so executada no banco de dados, a aplicação continuará recebo e executando outras queries usando as demais conexões armazenadas no pool. No Rails será criado um novo pool para cada execução do método establish_connection. Em outras palavras, cada banco de dados cadastrado no arquivo database.yml terá seu próprio pool de conexões. O pool começa vazio e vai cresco até o limite de 5 conexões (padrão), mas você pode aumentar este limite acrescentando a opção pool na configuração do banco de dados. development: adapter: mysql host: localhost username: myuser password: mypass database: somedatabase pool: 10 wait_timeout: 15 16

Capitulo 1: ActiveRecord Se nenhuma das conexões estiver disponível, uma thread irá esperar durante 5 segundos (padrão) antes de desistir de esperar por uma conexão. Este tempo também pode ser configurado adicionando a chave wait_timeout na configuração do banco de dados. Se você desejar usar o pool de conexões fora do ActionPack, existe o método ActiveRecord::Base.connection_pool que permite que você manualmente faça o checkout/checkin das conexões. Não esqueça de fazer o checkin quando terminar de usar a conexão. connection = ActiveRecord::Base.connection_pool.checkout # faz alguma coisa no banco de dados ActiveRecord::Base.connection_pool.checkin(connection) Você também pode usar o método ActiveRecord::Base.connection_pool.with_connection que já faz o checkout/ checkin automaticamente para você, tornando-se uma opção mais segura. ActiveRecord::Base.connection_pool.with_connection do connection # faz alguma coisa no banco de dados MIGRATIONS TRANSACIONAIS NO POSTGRESQL Quando uma migration está em execução e um erro ocorre, tudo que já foi executado será aplicado ao banco de dados, mas tudo que estiver após o erro, não será aplicado. Além disso a migration será marcada como concluída. Isto pode dar uma certa dor de cabeça para corrigir. 17

Ruby on Rails 2.2 - O que há de novo? Mas, se o banco de dados que você estiver usando tiver suporte a DDL rollbacks em transações, então ele pode fazer uso deste recurso para desfazer tudo que foi feito antes do erro. O problema é que nem todos os bancos de dados possuem este recurso. O MySQL, por exemplo não possuí. Mas o PostgreSQL, SQL Server e outros bancos possuem. Neste caso o código do Rails foi atualizado para permitir o uso de transações em migrations quando você estiver usando estes bancos de dados. Embora o Rails permita este recurso, o adapter do banco deve ser atualizado (apenas fazo com que o método supports_ddl_transactions? retorne true) para fazer uso de transações. Até o lançamento deste livro somente o do PostgreSQL parecia ter sido atualizado. NOVA VERSÃO DESTRUTIVA DOS MÉTODOS DE PESQUISA DO ACTIVERECORD Os métodos dinâmicos de pesquisa do ActiveRecord receberam uma versão destrutiva, que dispara um erro do tipo RecordNotFound caso nenhum registro seja encontrado, ao invés de apenas retornar nil como acontece com a versão original. Para usar esta versão destrutiva, basta adicionar o sinal de exclamação no final do método. Veja um exemplo: Topic.find_by_title!("The First Topic!") # => ActiveRecord::RecordNotFound MELHORANDO A PERFORMANCE NOS MÉTODOS ASSOCIATION_IDS Se você tiver dois modelos: Post e Comment. Onde um post tem muitos (has_many) comentários. Se você executar: 18

Capitulo 1: ActiveRecord Post.first.comment_ids O Rails usará a seguinte query para recuperar os ids: SELECT * FROM `comments` WHERE (`comments`.post_id = 1) Mas neste caso, não precisamos dos objetos inteiros. A seguinte query seria mais do que suficiente para o funcionamento deste método, além de possuir uma performance melhor: SELECT `comments`.id FROM `comments` WHERE (`comments`.post_id = 1) Tanto para associações has_many, como para associações has_many incluir esta melhora de performance a partir desta versão. :through o código do Rails foi alterado para MAIS UM FINDER DINÂMICO Aumentando o número de finders dinâmicos do find_by e o find_all_by. ActiveRecord, agora temos o find_last_by. Já tínhamos os famosos Além de simplificar, ficou muito mais elegante recuperar o último comentário feito por um usuário, por exemplo. Veja: Comment.find_last_by_author("Carlos Brando") # é a mesma coisa que Comment.last(:conditions => { :author => "Carlos Brando" }) 19

Ruby on Rails 2.2 - O que há de novo? SUPORTE À OPÇÃO :LIMIT NO MÉTODO UPDATE_ALL O método update_all agora também funciona com a opção :limit. Isto é muito bom porque garante que ao usar o update_all em associações has_many que façam uso da opção :limit tudo funcionará adequadamente. NOVAS OPÇÕES PARA O MÉTODO COMPOSED_OF O método composed_of recebeu duas novas opções: :constructor e :converter. A opção :constructor pode receber um símbolo com o nome de um método ou um Proc. Por padrão, a classe de composição é criada através do método new, recebo todos os atributos mapeadas como parâmetros, exatamente na ordem que em foram mapeados. Se por algum motivo a sua classe não aceitar esta convenção, você deve fazer uso da opção :constructor. Com ela você pode alterar a forma como sua classe deve ser criada. Veja um exemplo retirado da própria documentação do Rails: composed_of :ip_address, :class_name => 'IPAddr', :mapping => %w(ip to_i), :constructor => Proc.new { ip IPAddr.new(ip, Socket::AF_INET) } No exemplo, como você pode ver, ao criar uma nova instancia da classe IPAddr é necessário informar mais um parâmetro ao construtor. Fazo uso da opção :constructor isto se torna bem simples. Quanto a opção :converter, ela também aceita um símbolo que represente um método da classe informada na opção :class_name ou um Proc, e é disparado quando um valor diferente de uma instância da classe informada for passado para a propriedade criada, o que torna necessário uma conversão. Mais um exemplo: 20

Capitulo 1: ActiveRecord composed_of :balance, :class_name => "Money", :mapping => %w(balance amount), :converter => Proc.new { balance Money.parse(balance) } No exemplo acima o método balance= sempre estará esperando por uma instancia da classe Money, mas caso um outro tipo de objeto seja informado ele deverá ser convertido usando o método parse do objeto Money. Com esta nova opção não devemos mais usar o bloco de conversão que o método permitia antes, a conversão deve ser feita através do uso da opção :converter. ATUALIZANDO UMA ASSOCIAÇÃO ATRAVÉS DE SUA FOREIGN KEY Não sei dizer se isto é um bug ou não, mas na minha opinião isto representava um problema. Veja o código abaixo, onde tento alterar a conta de um usuário usando sua foreign key em um projeto Rails 2.1 ou anterior: class User < ActiveRecord::Base belongs_to :account user = User.first # => #<User id: 1, login: "admin", account_id: 1> user.account # => #<Account id: 1, name: "My Account"> user.account_id = 2 # => 2 21

Ruby on Rails 2.2 - O que há de novo? user.account # => #<Account id: 1, name: "My Account"> Note que estou alterando a conta do usuário, mas a associação não foi atualizada. Mesmo depois de salvar o objeto user, se ele não for recarregado, a associação continuará mostrando a conta errada. No Rails 2.2 este problema foi corrigido. Veja: class Comment < ActiveRecord::Base belongs_to :post comment = Comment.first # => #<Comment id: 1> >> comment.post # => #<Post id: 1> >> comment.post_id = 2 # => 2 >> comment.post # => #<Post id: 2> Veja que ao alterar o post por meio de sua foreign key, automaticamente a associação foi atualizada. ALIAS_ATTRIBUTE FUNCIONANDO COM DIRTY OBJECTS Para enter esta alteração, vamos precisar analisar o mesmo código so executado em uma versão mais antiga do Rails e depois nesta nova versão. Vamos pegar um modelo como exemplo: 22

Capitulo 1: ActiveRecord class Comment < ActiveRecord::Base alias_attribute :text, :body Note que estou usando o método alias_attribute para criar um alias para o atributo body com o nome de text. Na teoria este método deveria replicar todos os métodos de leitura, escrita, pesquisa e qualquer outro que envolva o atributo body. Mas vejamos um exemplo so executado no Rails 2.1 ou anterior: c = Comment.first # => #<Comment id: 1, body: "my comment"> c.body # => "my comment" c.text # => "my comment" c.body = "a new message" # => "a new message" c.body_changed? # => true c.text_changed? # => NoMethodError: undefined method `text_changed?'... Ao executar o método text_changed? temos um erro, porque o alias_attribute não estava replicando os métodos de rastreamento, mas isto já foi corrigido. Veja o mesmo código executado agora em um projeto Rails 2.2: c = Comment.first # => #<Comment id: 1, body: "my comment"> c.body 23

Ruby on Rails 2.2 - O que há de novo? # => "my comment" c.text # => "my comment" c.body = "a new message" # => "a new message" c.body_changed? # => true c.text_changed? # => true c.text_change # => ["my comment", "a new message"] NOVO MÉTODO DE INSTÂNCIA MODEL#DELETE Para tornar o ActiveRecord mais consistente foi adicionado o método de instância Model#delete. Ele é similar ao método de classe com o mesmo nome. O método delete, diferente do método destroy, apaga o registro do banco de dados sem disparar callbacks, como o before_destroy e o after_destroy. Este método também não aplicará nenhuma das regras impostas na associação através de cláusulas como client = Client.find(1) client.delete 24 :depent.

Capitulo 1: ActiveRecord TORNANDO ATRIBUTOS DO ACTIVERECORD PRIVADOS No Rails 2.2 você poderá definir atributos do ActiveRecord como private. Como estes atributos são criados via metaprogramação, até agora isto era impossível. Para enter como isto funcionará, vamos tornar o atributo name da classe User privado: class User < ActiveRecord::Base private def name "I'm private" Agora ao tentar recuperar o valor do atributo name: user = User.first # => #<User id: 1, name: "teste"> user.name # => NoMethodError: undefined method `NoMethodError' for #<User:0x234df08> Veja que uma exceção NoMethodError foi disparada ao executar o método que agora é privado. Por outro lado eu posso alterar o nome do usuário, já que o método name= é ainda público. user.name = "Carlos" # => "Carlos" 25

Ruby on Rails 2.2 - O que há de novo? Capitulo 2 ActiveSupport ARRAY#SECOND ATÉ ARRAY#TENTH No objeto Array já tínhamos o método first e last, então porque não ter também os métodos second, third, fourth e assim por diante? É isso mesmo, foram acrescentados ao objeto Array os métodos que vão do second (segundo) até o tenth (décimo), que servem para retornar o objeto especifico dentro do Array (o terceiro objeto do array, por exemplo). Vamos aos exemplos: array = (1..10).to_a array.second array.third array.fourth 26 # => array[1] # => array[2] # => array[3]

Capitulo 2: ActiveSupport array.fifth array.sixth array.seventh array.eighth array.ninth array.tenth # # # # # # => => => => => => array[4] array[5] array[6] array[7] array[8] array[9] NOVO MÉTODO ENUMERABLE#MANY? Um novo método foi adicionado ao módulo Enumerable: many?. E como o nome mesmo diz, ele verifica se a coleção possui mais de um objeto, ou em outras palavras se tem muitos objetos associados. Este método é um alias para collection.size > 1. Vamos ver alguns exemplos: >> [].many? # => false >> [ 1 ].many? # => false >> [ 1, 2 ].many? # => true Além deste formato dado nos exemplos, este método também recebeu uma nova implementação permitindo que ele aceite blocos, que funciona exatamente como o método any?. Vamos aos exemplos: >> x = %w{ a b c b c } # => ["a", "b", "c", "b", "c"] 27

Ruby on Rails 2.2 - O que há de novo? >> x.many? # => true >> x.many? { y y == 'a' } # => false >> x.many? { y y == 'b' } # => true # um outro exemplo... people.many? { p p.age > 26 } Apenas para relembrar e reforçar, este método só retornará true se mais de um objeto passar nas condições quando usado o bloco, e quando a coleção tiver mais de um objeto quando usado sem condicionais. Só uma curiosidade, o método inicialmente se chamaria several?, mas foi alterado para many? depois. CRIE REGRAS PARA O STRING#HUMANIZE Já faz um certo tempo que Pratik Naik estava tentando colocar este patch no Rails e parece que finalmente conseguiu. No arquivo config/initializers/inflections.rb você tem a opção de acrescentar novas inflexões para pluralização, singularização e outros: Inflector.inflections do inflect inflect.plural /^(ox)$/i, '\1en' inflect.singular /^(ox)en/i, '\1' inflect.irregular 'person', 'people' 28

Capitulo 2: ActiveSupport inflect.uncountable %w( fish sheep ) No Rails 2.2 você também pode incluir inflexões para o método exemplos: humanize da classe String. Vamos aos famosos 'jargon_cnt'.humanize # => "Jargon cnt" 'nomedojogo'.humanize # => "Nomedojogo" ActiveSupport::Inflector.inflections do inflect inflect.human(/_cnt$/i, '\1_count') inflect.human('nomedojogo', 'Nome do Jogo') 'jargon_cnt'.humanize # => "Jargon count" 'nomedojogo'.humanize # => "Nome do jogo" INTRODUZINDO MEMOIZABLE PARA CACHE DE ATRIBUTOS Performance é coisa séria, e um dos métodos mais usados para aumentar a velocidade de execução em códigos é o uso de cache. Quem nunca fez algo assim? class Person < ActiveRecord::Base def age @age = um_calculo_muito_complexo Nesta versão do Rails temos uma forma mais elegante de fazer isto usando o método memoize (é memoize mesmo e não memorize). Vamos alterar o exemplo acima para funcionar com esta nova funcionalidade: 29

Ruby on Rails 2.2 - O que há de novo? class Person < ActiveRecord::Base def age um_calculo_muito_complexo memoize :age O método age será executado apenas uma vez e o seu retorno será armazenado e retornado em futuras chamadas ao método. Só existe uma diferença entre os dois códigos acima. No primeiro, como o método é executado todas as vezes, se o valor armazenado na variável @age for nil ou false o cálculo (muito complexo) será executado novamente até termos a idade da pessoa. No segundo exemplo, o método age só será executado uma vez e o valor retornado será sempre devolvido nas próximas chamadas, mesmo que seja nil ou false. Se em algum momento você precisar desligar ou religar o cache em propriedade marcadas com o memoize, você pode fazer uso dos métodos unmemoize_all e memoize_all. @person = Person.first # Para desligar o cache do método age @person.unmemoize_all # Para ligar novamente o cache do método age apenas @person.memoize_all 30

Capitulo 2: ActiveSupport NOVO MÉTODO OBJECT#PRESENT? Um novo método foi acrescentado à classe Object. O método present? é o equivalente a!object#blank?. Em outras palavras um objeto está presente se ele não for vazio. Mas o que é um objeto vazio? class EmptyTrue def empty?() true; a b c d e g g h = = = = = = = = EmptyTrue.new nil false '' ' ' " \n\t \r " [] {} a.present? b.present? c.present? d.present? e.present? f.present? g.present? h.present? # # # # # # # # => => => => => => => => false false false false false false false false Todos estes objetos são vazios ou não estão presentes. Mas, muito cuidado, algumas pessoas tem confundido as coisas. Veja alguns exemplos de objetos que NÃO estão vazios, ou seja, estão presentes: 31

Ruby on Rails 2.2 - O que há de novo? class EmptyFalse def empty?() false; a b c d e f g h = = = = = = = = EmptyFalse.new Object.new true 0 1 'a' [nil] { nil => 0 } a.present? b.present? c.present? d.present? e.present? f.present? g.present? h.present? # # # # # # # # => => => => => => => => true true true true true true true true Qualquer objeto que contenha um valor, está presente, isto vale até mesmo para um porque o Array não está vazio. Array preenchido com um nil, STRINGINQUIRER Uma nova classe foi incluída ao Rails, a classe StringInquirer. Para enter como funciona, vou ter de explicar usando alguns exemplos. Vamos criar uma classe chamada Cliente que contém um método que retorna o status do cliente: 32

Capitulo 2: ActiveSupport class Cliente def status "ativo" c = Cliente.new c.status # => "ativo" c.status == "ativo" # => true c.status == "inativo" # => false Ok, até aqui tudo normal. Agora vou modificar a implementação do método status usando a classe StringInquirer, sempre lembrando que o retorno do método status pode vir de uma coluna do banco de dados (claro), isto é apenas um exemplo. class Cliente def status ActiveSupport::StringInquirer.new("ativo") c = Cliente.new c.status # => "ativo" # Agora vem a grande diferença: c.status.ativo? # => true 33

Ruby on Rails 2.2 - O que há de novo? c.status.inativo? # => false Para verificar se o status do cliente é o esperado, ao invés de comparar status e o sinal de interrogação. Strings, eu uso um método com o valor do Claro que isto já começou a ser usado no próprio Rails. Por exemplo, caso você precise verificar se o Rails foi carregado em ambiente de produção, você pode substituir o velho Rails.env == "production", por: Rails.env.production? NOVA SINTAXE PARA TESTES Uma nova forma de se declarar testes foi adicionada ao Rails, usando declarações test/do. Veja: test "verify something" do #... Este é o novo padrão para testes do Rails, veja como ficou um arquivo de teste unitário recém criado nesta versão: require 'test_helper' class PostTest < ActiveSupport::TestCase # Replace this with your real tests. test "the truth" do assert true 34

Capitulo 2: ActiveSupport A forma convencional, usando métodos, também continuará funcionando, então nossos testes antigos não quebrarão. LIGANDO E DESLIGANDO CARGA DE DEPENDÊNCIAS Um novo parâmetro de inicialização foi adicionado ao Rails, a fim de ligar ou desligar a carga de novas classes durante uma requisição. config.depency_loading = true # ou config.depency_loading = false Se depency_loading for verdadeiro, durante uma requisição o Rails estará apto a carregar em memória qualquer classe que não tenha sido inicialmente carregada durante a inicialização do projeto. Caso ele seja falso, estas classes serão ignoradas. Se você for executar seu projeto em um ambiente de threads concorrentes deve desabilitar esta opção e carregar todas estas classes usando eager load ou através do método require na inicialização do sistema. FILE.ATOMIC_WRITE COPIA AS PERMISSÕES DO ARQUIVO ORIGINAL Talvez alguns não conheçam o método File.atomic_write. Ele serve para escrever arquivos de forma atômica. Isto pode ser muito útil em situações onde você não quer que outros processos ou threads vejam um arquivo escrito pela metade. File.atomic_write("important.file") do file file.write("hello") 35