Você está na página 1de 289

Rails para sua Diverso e Lucro

Copyright 2006 Ronaldo Melo Ferraz Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1. License.. Permiss/o 0 dada para copiar, distribuir e/ou modificar esse documento sob os termos da Licen1a de Documenta1/o Li"re GNU, Vers/o 1. ou 2ua!2uer outra "ers/o posterior da mesma pub!icada pe!a Free #oft$are Foundation% sem #e13es &n"ariantes, sem )e*tos de (apa Fronta!, e sem )e*tos de 4uarta (apa. Uma c5pia da !icen1a est6 inc!u7da na se1/o cu8o t7tu!o 0 .GNU Free Documentation License.. .9ai!s., .9uby on 9ai!s., e o !ogotipo do 9ai!s s/o marcas registradas de Da"id :einemeier :ansson, com todos os diretos reser"ados. ;s nomes e !ogotipo s/o usados a2ui com permiss/o. )odas as demais marcas registradas s/o propriedade de seus respecti"os donos, com todos os direitos reser"ados. or any !ater "ersion pub!ished by the Free #oft$are Foundation% $ith no &n"ariant #ections, no Front' (o"er )e*ts, and no +ac,'(o"er )e*ts. - copy of the !icense is inc!uded in the section entit!ed .GNU Free Documentation

Contedo
Rails para sua Diverso e Lucro......................................................................................................1 Aqui h rubis................................................................................................................................4 Ps e picaretas.............................................................................................................................5 Comean o a aplicao................................................................................................................! Primeiros passos......................................................................................................................! Con"i#uran o o banco e a os............................................................................................1$ %eran o mi#ra&es e mo elos e a os...............................................................................1' ()C.......................................................................................................................................** + primeiro controller.............................................................................................................*' La,outs..................................................................................................................................*! Roteamento...........................................................................................................................'* -ca""ol in#.............................................................................................................................'4 )ali a&es..............................................................................................................................41 .m se#un o controller..........................................................................................................44 /0ten en o um mo elo e a os..........................................................................................1* .san o helpers......................................................................................................................1' Relacionamentos...................................................................................................................12 3elon#s to..............................................................................................................................!5 4as man,...............................................................................................................................5! 4as one..................................................................................................................................52 4as man,6 throu#h................................................................................................................2$ Avanan o no Rails....................................................................................................................21 7iltros....................................................................................................................................21 .ploa s................................................................................................................................1$! Callbac8s.............................................................................................................................115 Plu#ins.................................................................................................................................112 4as an belon#s to man,....................................................................................................1*' /scopos................................................................................................................................1'4 7iltros aroun ......................................................................................................................141 9(L.....................................................................................................................................145 Autenticao 4::P..............................................................................................................15$ /nvian o e;mails.................................................................................................................155 Depuran o aplica&es.........................................................................................................11$ Associa&es polim<r"icas.....................................................................................................11* (< ulos...............................................................................................................................115
*

A=a0......................................................................................................................................1!$ A#in o como uma lista........................................................................................................125 :rans"orman o um mo elo e a os..................................................................................122 Continuan o com A=a0.........................................................................................................*$4 De#ra ao em A=a0............................................................................................................**5 Avanan o um pouco mais.......................................................................................................**! Roteamento avana o.........................................................................................................**5 Cachin#...............................................................................................................................*'' :ra uo6 .nico e e %lobali>ao......................................................................................*51 -e#urana............................................................................................................................*51 .nit :estin#.........................................................................................................................*1$ ?mplantao.........................................................................................................................*!5 Ambientes e Desenvolvimento...........................................................................................*!5 Ra8e a seu servio...............................................................................................................*!2 )iven o no limite.................................................................................................................*5$ + que "alta...........................................................................................................................*51 Concluso.................................................................................................................................*51 Ap@n ice AA %B. 7ree Documentation License......................................................................*5* $. PR/A(3L/......................................................................................................................*5* 1. APPL?CA3?L?:C ABD D/7?B?:?+B-...............................................................................*5' *. )/R3A:?( C+PC?B%......................................................................................................*54 '. C+PC?B% ?B D.AB:?:C.................................................................................................*54 4. (+D?7?CA:?+B-............................................................................................................*55 5. C+(3?B?B% D+C.(/B:-............................................................................................*5! 1. C+LL/C:?+B- +7 D+C.(/B:-...................................................................................*5! !. A%%R/%A:?+B E?:4 ?BD/P/BD/B: E+RF-.............................................................*5! 5. :RAB-LA:?+B................................................................................................................*55 2. :/R(?BA:?+B................................................................................................................*55 1$. 7.:.R/ R/)?-?+B- +7 :4?- L?C/B-/.....................................................................*55 4oG to use this License "or ,our ocuments.......................................................................*55

'

Aqui h rubis
4 pouco mais e ois anos atrs eu escobria o Rails. Procuran o por um Gi8i para uso pessoal6 eu topei com uma aplicao escrita em Rub,6 uma lin#ua#em pro#ramao queHapesar a minha pai0o pelo assuntoHeu conhecia apenas por meio e

e men&es

espor icas no blo# o um ami#o. A aplicao era o ?nsti8i e eu a instalei minutos epois e terminar e ler suas caracterIsticas6 que me aten iam per"eitamente. (ais tar e6 investi#an o o c< i#o o ?nsti8i6 eu escobri que ele "ora esenvolvi o em um novo "rameGor8

para aplica&es Eeb chama o Rub, on Rails6 ou simplesmente Rails. A espeito e meu interesse anti#o por to o e qualquer "rameGor8 Eeb6 "oi somente ap<s um m@s que eu me eci i veri"icar o que era o Rails. Dois anos epois6 quase to o o meu esenvolvimento Eeb atual J "eito em Rails e eu ain a uso o ?nsti8iH

ironicamente6 a mesma verso que eu bai0ei h tanto tempo atrs. Duan o comecei a usar o Rails6 uma as primeiras coisas que eu "i> "oi elaborar um tutorial para a=u ar as

pessoas que estavam curiosas sobre o assunto a se "amiliari>arem com o ambiente. + tutorial era bem simples e aten ia a um prop<sito bsicoA mostrar a al#uJm que = conhecia pro#ramao Eeb o que era esse novo "rameGor8 quanti a e o qual to o mun o estava "alan o e o que ele realmente po ia "a>er. Des e que os arquivos mais bai0a os o meu servi or e6 =ul#an o pela liberei esse tutorial6 ele continua sen o um cumpri o plenamente. + presente tutorial tem um novo ob=etivoA ir alJm o bsico e mostrar mais o que o Rails J capa> e "a>er6 consi eran o principalmente o que "oi intro u>i o a partir elabora o com base na verso $.2.' e a verso 1.1 o mesmo. + tutorial anterior "oi e es e ento muita coisa mu ouK vrias novas "acili a es "oram

e e;mails que eu ain a recebo sobre o mesmo6 acre ito que o ob=etivo proposto no mesmo "oi

intro u>i as tornan o o Rails ain a mais po eroso e "le0Ivel6 levan o o mesmo a um novo patamar pro utivi a e6 que inclui a possibili a e e aproveitar plenamente os recursos a to "ala a Eeb *.$. .m se#un o ob=etivo J que esse tutorial tambJm possa servir re"er@ncia em um curso avana o. Com base nisso6 o tutorial procura equilibrar uma intro uo completa ao Rails com uma panorLmica t<picos mais elabora os que incluem6 entre outros6 a construo e e0tens&es para o "rameGor86 o uso relacionamentos mais so"istica os e uma apresentao e assuntos relaciona os ao uso e A=a0. Como o tutorial possui esses elaborao bem mais completa ois ob=etivos istintos6 muito o que J a o no comeo e 5 a 11 horas6 tratan o ain a que inicialH os principais recursos e Rails e servin o

e base aos que quiserem utili>;lo com e alavanca para um conhecimento mais

e to os os t<picos necessrios para um conhecimentoH

e e

o mesmo J uma o Rails. -en o

o primeiro tutorial6 atuali>an o o te0to para a verso 1.1


4

assim6 se voc@ = tem o conhecimento bsico necessrio e material novo e al#uns consi era&es a mais que po em ser relacionamentos entre mo elos e relacionamentos intro u>i os a partir a verso 1.1. Dentro e ambos os ob=etivos6 esse tutorial J volta o para e

ese=a pular o = sabe6 sinta;se M vonta e para o Rails6 al#uma se&es contJm e e al#uma valiaHum e0emplo J a seo sobre e al#uns tipos mais avana os

"a>er isso. /ntretanto6 como muitas coisas mu aram entre as vers&es a os6 que "ala tambJm

esenvolve ores = "amiliari>a os com al#um e tempo6 o tutorial assume e

ambiente

esenvolvimento Eeb6 se=a usan o Linu0 ou Ein oGs. Por ra>&es

que o esenvolve or = tenha conhecimento e pelo menos uma lin#ua#em e pro#ramao6 e um banco e a os relacional qualquer e que se=a capa> e estabelecer um ambiente para essa lin#ua#em e banco a os em sua plata"orma e escolha6 ou se=a6 que tenha o conhecimento tJcnico para acompanhar os passos a os no tutorial sem maiores problemas. + tutorial no assume6 porJm6 que o esenvolve or saiba "a>er o mesmo para o Rails e e0plica isso nos etalhes necessrios. .m certo conhecimento inteli#Ivel para qualquer o Rub, J requeri o6 embora a lin#ua#em se=a simples e po erosa o su"iciente ser esenvolve or com uma e0peri@ncia ra>ovel em outra lin#ua#em e alto nIvel.

Apesar isso6 esse tutorial po e no ser to "cil para esenvolve ores que este=am an o os seus primeiros passos em pro#ramao e em especial pro#ramao para a EebHembora eu acre ite esenvolve ores iniciantes possam se bene"iciar muito com o contato com uma lin#ua#em mais po erosa e com um

"rameGor8 mais elabora o.


.ma se#un a ressalva J que o tutorial "oi escrito sob o Linu06 utili>an o;se plata"orma. +n e houver necessi a e6 suporta a pelo Rails sem mais coman os e no c< i#o. Depois e to as as consi era&es acima6 meu conselho J somente umA iverso na hora e pro#ramar. /u ivirta;se. + cria or o Rails6 Davi as particulari a es essa

i"erenas para o Ein oGs sero nota as6 mas as conven&es e mu ar um ou ois etalhes na e0ecuo os

se#uiro o comum ao Linu0. Dito isso6 J per"eitamente possIvel aproveitar o tutorial em qualquer plata"orma o que a necessi a e

4einemeier 4ansson6 = isse em vrias ocasi&es que um os seus ob=etivos ao criar o Rails "oi evolver aos pro#rama ores a iria que ele conse#uiu isso. /nto6 se=a qual "oi o seu prop<sito ao ler esse tutorial6 aproveite bastante.

Ps e picaretas
Como ito acima6 o presente tutorial assume que voc@ tenha "amiliari a e com pro#ramao Eeb em #eral6 e com pelo menos um banco e a os relacional. /u usei o (,-DL na elaborao o tutorial por ele ser um banco e "cil instalao6 mas voc@ po e usar o que mais se a aptar ao seu ambiente6 principalmente a comple0i a e nesssa rea e que ele suporta os consi eran o que o Rails escon e a maior parte principais bancos e a os e0istentes no merca o. Para comear6 vamos assumir que voc@ tenha um banco e a os instala o e que este=a pronto para instalar o Rails e quaisquer outras bibliotecas necessrias. + primeiro passo ento J instalar o Rub,6 a lin#ua#em no
5

qual o mesmo "oi esenvolvi o. + Rub, J uma lin#ua#em e alto nIvel6 to completa quan o uma lin#ua#em po eria ser. -ua sinta0e J bem simples6 e lembra A a e /i""el6 com al#umas pita as voc@ leia o tutorial escrito pelo /ustquio e Perl em al#uns pontos. Como o ob=etivo Ran#el6 isponIvel no en ereo esse tutorial no J e0plicar ao Rub,6 se voc@ acha que precisa e uma intro uo M lin#ua#em6 eu recomen o que N:aDO se#uinteA http://eustaquiorangel.com/files#ruby. + :aD J conheci o e lon#a ata6 e seu tutorial J provavelmente a melhor intro uo ao Rub, em os primeiros livros sobre a

portu#u@s. Aproveitan o para "a>er uma mJ ia6 ele tambJm publicou um http://www.brasport.com.br/index.php?Escolha=8& i!ro= ""#8$. )oltan o M instalao o Rub,6 o processo J bem simples.

lin#ua#em em nosso i ioma. )oc@ po e encontrar mais in"orma&es sobre o livro no se#uinte en ereoA

Bo Ein oGs6 a melhor maneira J usar o Rub, +ne;Clic8 ?nstaller6 cu=a verso atual J a 1.5.5. /sse instala or po e ser bai0a o e http://rubyforge.org/pro%ects/rubyinstaller/ e basta ro ;lo para ter um ambiente Rub, completo para o Ein oGs6 incluin o ocumentao e e itores e te0to. /m istribui&es o Linu0 como o .buntu ou Debian6 com "acili a es para a instalao a pr<pria e aplicativos6 uma epen @ncias

maneira rpi a J usar as "erramentas

istribui&es para bai0ar os pacotes e

necessrias. .m problema6 entretanto6 J que normalmente a verso o Rub, isponIvel nessas istribui&es J a 1.5.*6 que no ser mais suporta a pelo Rails em breve. + presente tutorial ro a per"eitamente sob essa verso mas "oi basicamente esenvolvi o sob a verso 1.5.4. Assim6 se voc@ est utili>an o o Linu06 eu recomen o que voc@ compile a sua pr<pria verso o Rub,6 se=a a 1.5.4 ou a 1.5.5. A verso 1.5.5 J a estvel atualmente. Para compil;la6 utili>e o proce imento abai0oA

ronaldo@minerva:~$ ronaldo@minerva:~$ ronaldo@minerva:~$ ronaldo@minerva:~$ ronaldo@minerva:~$ ronaldo@minerva:~$

wget ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.8.5.tar.gz tar xvfz ruby-1.8.5.tar.gz d ruby-1.8.5 ./ onfigure --prefix!/u"r ma#e ma#e in"tall

Para veri"icar a verso instala a o Rub,6 use o se#uinte coman oA

ronaldo@minerva:~$ ruby -v ruby 1.8.$ %&''5-1&-&$( )i$8*-linux+

Bo meu caso6 estou usan o a Pltima verso estvel a 1.5.4. .ma ve> que o Rub, este=a instala o6 J hora e "a>er o mesmo com o Rails. + proce imento J bem simplesA
1

basta e0ecutar o coman o abai0o1A

ronaldo@minerva:~$ gem in"tall rail" --in lude-dependen ie"

&em J o #erencia or -use6 capa> bibliotecas

e pacotes

o Rub,6 similar em "uncionamento ao apt'get esenvolve or tenha que se preocupar com os

o Debian ou ao (a)* entro

o as o

e bai0ar os arquivos necessrios o Rub, sem que o

a Eeb e instal;los no local apropria o etalhes

o processo. (ais M o Rails se=am

"rente6 utili>aremos novamente o coman o para instalar outros pacotes que "acilitam a vi a esenvolve or Rails. + Pltimo parLmetro acima #arante que to as as instala as simultaneamente sem necessi a e e interveno. epen @ncias

Bovas vers&es o Rails so instala os por um processo similar. -e voc@ = bai0ou al#uma verso al#uma ve>6 use o mesmo coman o acima para atuali>ar a sua principalmente6 eve ser a Pnica usa a em um servi or pPblico. Com os passos acima "inali>a os e um banco esenvolvimento em Rails. e a os isponIvel6 voc@ est pronto para comear o istribuio para a verso mais recente6 lembran o6 e se#urana nas vers&es anteriores e e que a verso 1.1.1 corri#e um sJrio problema

Comeando a aplicao
PRIMEIROS PASSOS
)amos comear a trabalhar em uma aplicao bem simples. Como to o tutorial = pro u>i o na "ace a terra utili>a uma variao e blo#s6 lo=as virtuais6 a#en as6 livros e en ereos6 ou listas e coisas a "a>er6 vamos tentar al#o o %:D6 a meto olo#ia i"erenteA pro u>ir uma aplicao simples Allen. )i e usan o al#uns poucos conceitos e pro utivi a e cria a por Davi

%ettin# :hin#s Done6 por Davi


etalhes.

AllenHtra u>i o no 3rasil como A Arte

e 7a>er AcontecerHpara mais

+bviamente6 como o %:D J uma meto olo#ia comple0a em sua totali a e6 vamos nos "ocar somente em al#uns aspectos bsicos a mesma como conte0tos6 pro=etos6 e pr<0imas a&es. ?sso ser mais esses conceitos6 o resulta o "inal no estar6 J claro6 poli o para o uso o que irio. su"iciente para passarmos pela maioria os componentes o Rails. -en o o que estamos crian o meramente uma implementao li#eira Da mesma "orma6 voc@ no precisa enten er os processos vamos utili>ar so su"icientemente auto;e0plicativas. o %:D para se#uir o tutorialHas partes que

Lembre;se e que6 no Linu06 voc@ precisar e permiss&es su"icientes para e0ecutar o coman o acima6 possivelmente lo#an o como superusurioHa menos6 J claro6 que voc@ tenha instalan o o Rub, e o Rails em seu pr<prio iret<rio

home.
!

A primeira coisa a "a>er6 ento6 J criar o abai0oA

iret<rio

e trabalho

a aplicao. ?sso J "eito com o coman o

ronaldo@minerva:~/tmp$ rail" gtd reate reate app/ ontroller" reate app/,elper" reate app/model" reate app/view"/layout" reate onfig/environment" reate omponent" reate db reate do reate lib reate lib/ta"#" reate log reate publi /image" reate publi /-ava" ript" reate publi /"tyle",eet" reate " ript/performan e reate " ript/pro e"" reate te"t/fixture" reate te"t/fun tional reate te"t/integration reate te"t/mo #"/development reate te"t/mo #"/te"t reate te"t/unit reate vendor reate vendor/plugin" ...

+ coman o rails #era o esqueleto completo e uma aplicao6 pronta para ro ar. /sse coman o "oi cria o em seu sistema quan o voc@ instalou as bibliotecas necessrias. Caso voc@ no consi#a ro ;lo no Ein oGs6 J possIvel que as suas variveis iret<rio bin e ambiente no "oram atuali>a asHse=a porque a =anela e coman o em que voc@ est trabalhan o = estava aberta ou por al#um outro motivo qualquer. Besse caso6 #aranta que o a sua instalao Rub, este=a no caminho o Ein oGs6 a icionan o;o M sua varivel +,-*.+6 reinician o qualquer sesso e coman o con"orme o necessrio. Bo esqueleto #era o6 ca a parte a aplicao tem um local especI"ico para ser coloca o. ?sso eriva e uma as "iloso"ias por trs voc@ no precisa o Rails que po e ser escrita pela "rase Nconveno ao invJs e outra "orma6 teriam que se e con"i#uraoO. escritos em um Conveno6 nesse caso6 si#ni"ica que h um acor o entre o "rameGor8 e voc@6 o esenvolve or6 e mo o que e preocupar com certos etalhes que6 arquivo e con"i#urao. /ssa caracterIstica6 inclusive6 #erou uma pia a recorrente na comuni a e se#un o a qual muitas aplica&es Rails completas so menores consi eran o o monte o que um Pnico arquivo e con"i#urao e uma aplicao Qava. / e si#las que voc@ precisa conhecer para criar mesmo uma aplicao pequena em

qualquer "rameGor8 nessa Pltima lin#ua#em6 no J muito i"Icil acre itar que esse realmente se=a o caso. Bo Rails6 basta e0ecutar uma etermina a ao ou criar um etermina o arquivo e as coisas "uncionaro a maneira que voc@ ese=a e espera automaticamente6 sem necessi a e e qualquer trabalho a icional. A princIpio isso po e parecer um pouco restritivo6 mas na prtica "unciona per"eitamente. / sen o
5

e0tremamente "le0Ivel6 o Rails permite que voc@ mu e qualquer coisa que precise6 quan o precisar. Bo vamos entrar em etalhes sobre a estrutura e iret<rios a#ora porque ela "icar evi ente M me i a o tempo6

que avanarmos no tutorial. Bo se preocupeA ela J bem l<#ica e6 na maior parte automaticamente #erencia a pelo Rails. Para "ins o presente tutorial6 vamos se#uir a conveno

o coman o acima e ro ar to os os outros que e te0to qualquer. Para o

precisarmos

iretamente6 mo i"ican o os arquivos necessrios em um e itor

esenvolvimento

irio6 porJm6 e0istem ambientes especI"icos para o Rails com "acili a es pr<prias para a

lin#ua#em Rub, e para os etalhes o "rameGor8. 7alaremos um pouco mais sobre isso epois. A#ora que temos uma aplicao bsica6 vamos ro ;la e ver o resulta o. .ma as vanta#ens o Rails J que o ciclo e co i"icar;ro ar;e;testar J bem rpi o. 3asta "a>er uma e recarre#ar processos6 esperar a

alterao para ver ime iatamente o resulta o6 sem a necessi a e compilao que "a>er no Rails J reiniciar o servi or Eeb no caso

a aplicao ou envi;la para um servi or especialmente prepara o. + m0imo que voc@ ter e al#uma mu ana "un amental na con"i#urao

bsica a aplicao6 al#o que ocorre com pouca "reqR@ncia. Para "acilitar a vi a6 o Rails vem com seu pr<prio servi or Eeb6 utili>an o as bibliotecas Para ro ar o servi or6 basta usar um Sve=a o iret<rio script sob o esqueleto a aplicaoT. + coman o6 e0ecuta o entro o iret<rio a aplicao6 J o se#uinte*A o pr<prio Rub,.

os scripts utilitrios presentes em ca a aplicao #era a pelo Rails

ronaldo@minerva:~/tmp/gtd$ " ript/"erver !. /ooting 01/ri #... !. 2ail" appli ation "tarted on ,ttp://'.'.'.':3''' !. 4trl-4 to ",utdown "erver5 all wit, --,elp for option" )&''*-'6-&' 1':31:$'+ 789: 01/ri # 1.3.1 )&''*-'6-&' 1':31:$'+ 789: ruby 1.8.$ %&''5-1&-&$( )i$8*-linux+ )&''*-'6-&' 1':31:$'+ 789: 01/ri #::;<<=>erver?"tart: pid!8&*& port!3'''

Como voc@ po er ver6 o coman o inicia uma instLncia o servi or E/3ric86 capa> e servir aplica&es Rails sem necessi a e e qualquer con"i#urao a icional. + servi or ro a localmente e recebe requisi&es na e receber requisi&es porta '$$$. -en o um servi or simples e embuti o6 o E/3ric8 no J capa> simultLneas6 mas permite que testemos per"eitamente a nossa aplicao. Acessan o o en ereo a aplicao voc@ tem o se#uinteA

Bo Ein oGs6 ser necessrio pre"i0ar o coman o com uma invocao ao rub,6 script/ser!er. ?sso acontece porque6 no Ein oGs6 o script usa o no J a instalao o Rub, tiver si o "eita usan o o N+ne;Clic8 ?nstallerO. 2

a se#uinte "ormaA ruby/

iretamente e0ecutvel6 a menos6 J claro6

que voc@ este=a usan o um ambiente como o C,#Gin. Arquivos com a e0tenso .rb6 porJm6 sero e0ecutveis6 quan o

Como mostra o acima6 temos uma aplicao inicial ro an o que6 inclusive6 mostra quais so os pr<0imos passos para continuar o esenvolvimento a mesma.

CONFIGURANDO O BANCO DE DADOS


)amos acatar a su#esto a p#ina inicial e criar e con"i#urar o banco e a os a aplicao. /sse primeiro passo J muito importante porque o Rails usa as in"orma&es proveniente o schema o banco e a os para #erar automaticamente arquivos e con"i#ura&es a icionais. /sse J mais um e0emplo e conveno ao invJs e con"i#urao. Dessa "orma6 #arantir que o banco est "uncionan o corretamente6 con"i#ura o para uso a aplicao6 J o passo inicial e qualquer esenvolvimento em Rails. + arquivo e con"i#urao e banco e a os se chama a database.yml e est locali>a o no iret<rio

config6 =unto com os emais arquivos e con"i#urao a aplicao.

1$

/sse arquivo6 removen o os comentrios Sas linhas inicia as com UT6 tem o se#uinte "ormatoA

development: adapter: my"@l databa"e: gtdAdevelopment u"ername: root pa""word: ,o"t: lo al,o"t te"t: adapter: my"@l databa"e: gtdAte"t u"ername: root pa""word: ,o"t: lo al,o"t produ tion: adapter: my"@l databa"e: gtdAprodu tion u"ername: root pa""word: ,o"t: lo al,o"t

A e0tensao .,ml se re"ere ao "ormato o arquivo6 que utili>a uma lin#ua#em e omInio chama a CA(L. Por hora6 basta saber que J uma lin#ua#em e seriali>ao e a os "avoreci a por esenvolve ores Rub, e Rails. )oc@ po e encontrar mais in"orma&es sobre a mesma na ocumentao o"icial o Rub,. .ma aplicao Rails #eralmente utili>a tr@s bancos ambiente e esenvolvimento pa ro. .m banco e a os J utili>a o para o esenvolvimento6 on e to as as mu anas so aplica as. /sse banco e pro uo6 on e mo i"ica&es somente so aplica as uma ve> que e a os6 como emonstra o acima6 um para ca a

tem seu correspon ente em um banco

este=am completas. + arquivo permite con"i#urar6 inclusive6 um banco remoto para on e suas mo i"ica&es "inais sero re ireciona asHembora #eralmente se=a melhor utili>ar um outro mJto o e implantao6 como veremos mais a iante. + terceiro banco mostra o acima J um banco e testes6 utili>a o pelo Rails para a e0ecuo e unit testin#. /sse banco deve ser manti o necessariamente M parte = que to os os a os e tabelas presentes no mesmo so e0cluI os e recria os a ca a teste completo e"etua o na aplicao. )amos criar o banco a#oraA

ronaldo@minerva:~/tmp/gtd$ my"@l -u root -p 1nter pa""word: 0el ome to t,e By>CD monitor. 4ommand" end wit, 5 or Eg. Four By>CD onne tion id i" 8 to "erver ver"ion: 5.'.&&-GebianA'ubuntu*.'*.&-log <ype H,elp5H or HE,H for ,elp. <ype HE H to my"@l. reate databa"e gtd5 Cuery :IJ 1 row affe ted %'.5* "e ( lear t,e buffer.

11

my"@l. reate databa"e gtdAte"t5 Cuery :IJ 1 row affe ted %'.53 "e ( my"@l. u"e gtd5 Gataba"e ,anged my"@l.

<odificando o ar2ui"o de configura1/o para desen"o!"imento !oca!, ter7amos a!go assim=

development: adapter: my"@l databa"e: gtd u"ername: root pa""word: ,o"t: lo al,o"t "o #et: /var/run/my"@ld/my"@ld."o # te"t: adapter: my"@l databa"e: gtdAte"t u"ername: root pa""word: ,o"t: lo al,o"t "o #et: /var/run/my"@ld/my"@ld."o # produ tion: development

Bo caso acima6 eu con"i#urei os banco queremos testar uma aplicao nas tambJm acrescentar o mJto o

e pro uo e

esenvolvimento para apontarem para o mesmo local

= que o esenvolvimento est limita o M minha mquina. /ssa J uma estratJ#ia interessante a usar quan o uas situa&es localmente sem nos preocuparmos em copiar o banco a o que al#uns coman os. /u precisei e transporte soc8et M con"i#urao = que em minha mquina6 to o momentoHmesmo que o Rails permita isso com pouco mais

especi"icamente6 o (,-DL no permite cone0&es e re e em sua con"i#urao pa ro. +utros tipos bancos e a os so con"i#ura os e e maneira similar6 mu an o o parLmetro adapter e e #erar uma arquivo e

quaisquer outras con"i#ura&es necessrias. .ma maneira mais simples con"i#urao especI"ico para o banco esqueleto a aplicao passan o um parLmetro para isso. Por e0emploA

a os que voc@ est usan o J = invocar o coman o para #erar o

rail" --databa"e!ora le gtd

+ coman o acima #era o mesmo esqueleto

a aplicao6 com a Pnica

i"erena

e que o arquivo

database.yml ser um pouco i"erente para levar em conta as i"erenas o +racle. )oltan o M nossa aplicao6 como um arquivo e con"i#urao importante "oi mu a o6 o servi or Eeb

precisa ser reinicia o. ?sso acontece porque ele somente l@ essas con"i#ura&es no inIcio e e0ecuo. /sse J um os raros casos em que um servi or e esenvolvimento precisa ser reinicia o = que o Rails recarre#a

1*

praticamente qualquer mo i"icao "eita na aplicao quan o est no mo o e esenvolvimento. A#ora temos uma aplicao e um banco esenvolvimento propriamente ito. Para acesso ao banco e a os6 o Rails usa classes e a os conheci as como mo els6 ou mo elos e a os. /ssas classes mascaram os "cil e intuitiva ao etalhes Ns<r i osO o acesso ao banco e a os provi encian o uma inter"ace e a os para esenvolve or. /m qualquer aplicao6 teremos pelo menos um mo elo e a os con"i#ura o. Com isso = po emos iniciar o processo e

utili>ar na mesma. / a maneira mais "cil e "a>er isso J criar automaticamente a tabela no banco e a os6 utili>an o um os scripts o Rails. + Rails automaticamente enten e que to as as tabelas cria as no banco para uso em mo elos6 ou classes e a os6 satis"aro a uas con i&esA tero um nome plural em in#l@s e tero uma chave primria surro#a a inteira e auto;incrementa a chama a i . V possIvel mu ar ambas as con i&es6 mas inicialmente "icaremos com elas para no ter que mo i"icar o que o Rails #era e usa automaticamente. Para "acilitar o esenvolvimento6 a aplicao esenvolvi a est em in#l@s6 que espero se=a simples o omine plenamente este i ioma. Consi eran o a

su"iciente mesmo para a compreenso

o leitor que no

pro"uso e termos em in#l@s em nossa rea acho que isso no ser um problema. + uso o in#l@s evita que tenhamos que pensar em al#uns etalhes e tra uo e #lobali>ao enquanto estamos apren en o o Rails. (ais no "im o tutorial e0plicaremos como mu ar al#umas as coisas que o Rails por como pa ro.

GERANDO MIGRAES E MODELOS DE DADOS


%eralmente um tutorial e Rails comea mostran o com po emos = a icionar al#umas a&es M inter"ace. e mi#ra&es e mo elos e a os. /ssa J uma opo e Comearemos6 entretan o6 com a #erao

esenvolvimento para o presente tutorial6 mas voc@ po e se#uir em qualquer ireo que achar melhor uma ve> que este=a esenvolven o suas pr<prias aplica&es. ?sso ito6 vamos continuar. Para manter portabili a e e "acilitar o controle e versionamento o banco e a os6 o Rails utili>a al#o e qualquer nature>a no

chama o mi#rations Smi#ra&esT. -o scripts em Rub, que utili>aremos a#ora. A primeira tabela que vamos criar ser a tabela

escreven o mo i"ica&es

banco e a os. (i#ra&es so a maneira mais "cil e acrescentar tabelas e classes e a os ao Rails e J o

e conte0tos. Conte0tos6 no %:D6 so6 basicamente6 os

ambientes on e uma ao ser e0ecuta a6 como6 por e0emplo6 casa6 escrit<rio6 e;mail6 tele"one6 etc. + nome J bem intuitivo e voc@ po e ler mais sobre o assunto o livro menciona o anteriormente. )amos #erar ento uma mi#rao para essa primeira mo i"icao no bancoA

ronaldo@minerva:~/tmp/gtd$ " ript/generate migration reate db/migrate

reateA ontext"

1'

reate

db/migrate/''1A reateA ontext".rb

+ script generate J uma as "erramentas cruciais o Rails que utili>aremos ao lon#o e to o nosso tutorial6 sen o usa o6 como o nome in ica6 para criar basicamente qualquer estrutura que precisamos em uma aplicao. + seu primeiro parLmetro J o tipo nome e ob=eto que estamos #eran o6 seu se#un o parLmetro J o e #erao. Bo caso acima6 esse ob=eto e quaisquer outros parLmetro a icionais in icam op&es

estamos #eran o uma mi#rao6 cu=o nome J create0contexts. Bo Rails6 e0istem muitas conven&es quanto ao uso e nomes6 que so se#ui as pelos coman os o mesmo6 com convers&es automticas quan o necessrio. Bo caso acima6 por e0emplo6 o nome que usamos ser automaticamente converti o em um nome alterna a6 como voc@ po er ver abai0o. + resulta o o coman o J um arquivo novo6 pre"i0a o pela verso a mi#rao6 que "oi cria o no iret<rio e classe6 que no Rub, so e0pressas com capitali>ao

db/migrate. /sse pre"i0o J usa o para controlar quais altera&es um banco precisa so"rer para che#ar a uma verso especI"ica. / itan o o arquivo6 temos o se#uinteA

la"" 4reate4ontext" K L tive2e ord::Bigration def "elf.up end def "elf.down end end

+ Rails criou uma classe

eriva a SWT

a classe -cti!e1ecord::2igration com o CXX6 CU e

ois mJto os. /sses e uma

mJto os6 por estarem pre"i0a os por sel"6 in icam no Rub, que os mesmos po em ser chama os iretamente na classe SmJto os estticos na terminolo#ia instLncia. + mJto o self.up/J utili>a o para e"etuar as mo i"ica&es. + seu oposto6 self.down6 J usa o para es"a>er essas mo i"ica&es caso voc@ este=a reverten o para uma verso anterior o banco. Depen en o a "orma como os mJto os "orem escritos6 eles sero realmente complementares. +bviamente J possIvel que mo i"ica&es se=am e"etua as que no so reversIveis. Besse caso6 o Rails emitir um erro se uma mi#rao para uma verso mais bai0a "or tenta a. )amos e itar o arquivo a#ora para incluir a tabela que ese=amos criarA o QavaT6 sem necessi a e

la"" 4reate4ontext" K L tive2e ord::Bigration def "elf.up reateAtable : ontext" do MtM

14

t. olumn :nameJ :"tring end end def "elf.down dropAtable : ontext" end end

Para e"etuar suas mi#ra&es6 o Rails utili>a uma lin#ua#em e banco e a os

omInio que permite especi"icar opera&es

e "orma abstrata6 que no est presa a um servi or especI"ico. V possIvel e0ecutar

opera&es iretamente via -DL no banco6 mas isso no J recomen a o por quebrar essa abstrao. Bo caso acima6 o mJto o create0table que sero a iciona as. 3locos so uma as partes mais interessantes o Rub, e vale a estu ar um pouco o que eles po em "a>er = que o uso os mesmos J e0tenso em qualquer aplicao na lin#ua#em6 incluin o o Rails. Bo Rub,6 os blocos so valores e primeira classe6 que po e ser atribuI os e manipula os como qualquer outro ob=eto. .m outro etalhe a manter em mente J o uso e0tensivo e sImbolos no Rub,. Bo caso acima6 o pr<prio nome a tabela J mesmos. )oltan o ao nosso c< i#o6 como a tabela ter somente uma coluna inicialmente6 que J o nome o conte0to6 enota o por um sImbolo. -Imbolos so similares a strin#s6 com a i"erena "un amental que os so internali>a os e e0istem com uma Pnica instLncia que permite um uso transparente e e"iciente entro e self.up serve para especi"icar a tabela que ser cria a.

/sse mJto o recebe um bloco como parLmetro Sin ica o pela palavra;chave doT que especi"ica as colunas

somente precisamos e uma linha6 i enti"ican o o nome a coluna e seu tipo. (ais M "rente veremos outros tipos e op&es. + mJto o self.down6 como e0plican o6 reali>a a operao inversa estruin o a tabela. A#ora J hora J parte e aplicar essa mi#rao ao banco6 subin o sua verso. Para isso6 temos o utilitrio ra3e6 que o ma3e6 sen o capa> e reali>ar tare"as escritas em um

o Rub,. + ra3e /J o equivalente Rub,

1a3efile6 a mesma "orma que o ma3e "a> uso e um 2a3efile. + Rails vem com seu pr<prio 1a3efile que permite a e0ecuo e vrias e suas tare"as necessrias6

incluin o db:migrate4 que aplica as mi#ra&es ain a no e"etua as a um banco. Ro amos o coman o a se#uinte "ormaA

ronaldo@minerva:~/tmp/gtd$ ra#e db:migrate %in /,ome/ronaldo/tmp/gtd( !! 4reate4ontext": migrating !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -- reateAtable%: ontext"( -. 1.&'86" !! 4reate4ontext": migrated %1.&'6&"( !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

15

-e observamos o banco a#ora6 teremos o se#uinte schemaA

ronaldo@minerva:~/tmp/gtd$ my"@l -u root -p gtd my"@l. ",ow table"5 N---------------N M <able"AinAgtd M N---------------N M ontext" M M " ,emaAinfo M N---------------N & row" in "et %'.'' "e (

Duas tabelas "oram cria as6 conte0ts e schemaYin"o. A primeira J a que especi"icamos. A se#un a in"orma&es o banco para o Rails6 para controlar o versionamento o mesmo. A tabela conte0ts "icou assimA

escreve

ronaldo@minerva:~/tmp/gtd$ my"@l -u root -p my"@l. de" ribe ontext"5 N-------N--------------N------N-----N---------N----------------N M 9ield M <ype M 8ull M Iey M Gefault M 1xtra M N-------N--------------N------N-----N---------N----------------N M id M int%11( M 8: M =27 M 8ODD M autoAin rement M M name M var ,ar%&55( M F1> M M 8ODD M M N-------N--------------N------N-----N---------N----------------N & row" in "et %'.'' "e (

Como voc@ po e ver6 no J preciso especi"icar a chave primria surro#a a6 que J automaticamente cria a pelo Rails. A tabela schemaYin"o possui os se#uintes a osA

ronaldo@minerva:~/tmp/gtd$ my"@l -u root -p gtd my"@l. "ele t P from " ,emaAinfo5 N---------N M ver"ion M N---------N M 1 M N---------N 1 row in "et %'.'' "e (

/sse nPmero e verso ser incrementa o ou ecrementa o epen en o a ireo a mi#rao. A mi#rao tambJm criou o arquivo db/schema.rb6 conten o uma representao po e ser usa a para recriar a estrutura outra tare"a o ra3e. + arquivo J auto;#era o e no eve ser mo i"ica o manualmente. -eu "ormato po e ser visto abai0oA o banco em Rub,6 que

o mesmo em qualquer banco suporta o pelo Rails6 usan o uma

11

? <,i" file i" autogenerated. 7n"tead of editing t,i" fileJ plea"e u"e t,e ? migration" feature of L tive2e ord to in rementally modify your databa"eJ and ? t,en regenerate t,i" " ,ema definition. L tive2e ord::> ,ema.define%:ver"ion !. 1( do reateAtable Q ontext"QJ :for e !. true do MtM t. olumn QnameQJ :"tring end end

Bote apenas que essa representao J limita a Ms tabelas em si e no inclui chaves estran#eiras6 tri##ers ou

store proce ures.


+ pr<0imo passo a#ora J criar a classe abai0oA e a os correspon ente M tabela. Para isso6 usamos o coman o

ronaldo@minerva:~/tmp/gtd$ " ript/generate model ontext exi"t" app/model"/ exi"t" te"t/unit/ exi"t" te"t/fixture"/ reate app/model"/ ontext.rb reate te"t/unit/ ontextAte"t.rb reate te"t/fixture"/ ontext".yml exi"t" db/migrate Lnot,er migration i" already named reateA ontext": db/migrate/''1A reateA ontext".rb

+ Rails utili>a uma estratJ#ia e esenvolvimento Sconheci as como patterns e maneira #eralT chama a e ()C S(o el;)ieG;ControllerT. /ssa estratJ#ia separa os componentes a aplicao em partes istintas que no s< "acilitam o esenvolvimento como tambJm "acilitam a manuteno. + que estamos ven o no momento so os mo els6 que correspon em M cama a a os6 implementa a no Rails por um componente estrutura e acesso ao banco e

enomina o ActiveRecor . + coman o acima #era to a

e suporte ao mo elo6 incluin o testes e mi#ra&es para o mesmo. Como #eramos a nossa

mi#rao inicial manualmente6 o Rails nos in"orma que = e0iste uma com o mesmo nome que ele preten ia #erar e que ele est pulan o esse passo. + arquivo responsvel pela implementao se#uinteA o mo elo est em app/model/context.rb e contJm apenas o

la"" 4ontext K L tive2e ord::/a"e end

/ssas

uas linhas6 apoia as pelo Rails6 = provi enciam uma rique>a a os no banco6 e e0ecutar uma sJrie

e implementao que nos permite

recuperar6 inserir e atuali>ar

e outras opera&es comple0as sem a

necessi a e e qualquer coman o -DL ireto.

1!

)amos criar a#ora um novo mo elo correspon en o M tabela mi#rao essa ve>. + coman o JA

e pro=etos. )amos

ei0ar que o Rails #ere a

ronaldo@minerva:~/tmp/gtd$ " ript/generate model pro-e t exi"t" app/model"/ exi"t" te"t/unit/ exi"t" te"t/fixture"/ reate app/model"/pro-e t.rb reate te"t/unit/pro-e tAte"t.rb reate te"t/fixture"/pro-e t".yml exi"t" db/migrate reate db/migrate/''&A reateApro-e t".rb

)oc@ po e ver que o Rails #erou um template a mi#rao6 e basta e it;laA

la"" 4reate=ro-e t" K L tive2e ord::Bigration def "elf.up reateAtable :pro-e t" do MtM ? t. olumn :nameJ :"tring end end def "elf.down dropAtable :pro-e t" end end

+ arquivo "inal seria6 com base no que pensamos atJ o momentoA

la"" 4reate=ro-e t" K L tive2e ord::Bigration def "elf.up reateAtable :pro-e t" do MtM t. olumn :nameJ :"tring t. olumn :de" riptionJ :text end end def "elf.down dropAtable :pro-e t" end end

)oc@ no precisa se preocupar em criar to os os campos inicialmente. )oc@ po e sempre usar outra mi#rao para isso. Ro an o o coman o ra3e para carre#ar as mi#ra&es mais uma ve>6 temos o se#uinteA

ronaldo@minerva:~/tmp/gtd$ ra#e db:migrate %in /,ome/ronaldo/tmp/gtd( !! 4reate=ro-e t": migrating !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -- reateAtable%:pro-e t"( -. '.18*3" !! 4reate=ro-e t": migrated %'.18*5"( !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

15

+ resulta o "inal o banco seriaA

ronaldo@minerva:~/tmp/gtd$ my"@l -u root -p gtd my"@l. ",ow table"5 N---------------N M <able"AinAgtd M N---------------N M ontext" M M pro-e t" M M " ,emaAinfo M N---------------N 3 row" in "et %'.'' "e ( my"@l. de" ribe pro-e t"5 N-------------N--------------N------N-----N---------N----------------N M 9ield M <ype M 8ull M Iey M Gefault M 1xtra M N-------------N--------------N------N-----N---------N----------------N M id M int%11( M 8: M =27 M 8ODD M autoAin rement M M name M var ,ar%&55( M F1> M M 8ODD M M M de" ription M text M F1> M M 8ODD M M N-------------N--------------N------N-----N---------N----------------N 3 row" in "et %'.'' "e ( my"@l. "ele t P from " ,emaAinfo5 N---------N M ver"ion M N---------N M & M N---------N 1 row in "et %'.'' "e (

/ o arquivo db/schema.rb a#ora contJmA

? <,i" file i" autogenerated. 7n"tead of editing t,i" fileJ plea"e u"e t,e ? migration" feature of L tive2e ord to in rementally modify your databa"eJ and ? t,en regenerate t,i" " ,ema definition. L tive2e ord::> ,ema.define%:ver"ion !. &( do reateAtable Q ontext"QJ :for e !. true do MtM t. olumn QnameQJ :"tring end reateAtable Qpro-e t"QJ :for e !. true do MtM t. olumn QnameQJ :"tring t. olumn Qde" riptionQJ :text end end

Para terminar6 vamos #erar a tabela e o mo elo e a&esA

ronaldo@minerva:~/tmp/gtd$ " ript/generate model a tion exi"t" app/model"/ exi"t" te"t/unit/ exi"t" te"t/fixture"/ reate app/model"/a tion.rb reate te"t/unit/a tionAte"t.rb reate te"t/fixture"/a tion".yml exi"t" db/migrate reate db/migrate/''3A reateAa tion".rb

12

A mi#rao para o mo elo seriaA

la"" 4reateL tion" K L tive2e ord::Bigration def "elf.up reateAtable :a tion" do MtM t. olumn :de" riptionJ :"tring t. olumn :doneJ :boolean t. olumn : reatedAatJ :datetime t. olumn : ompletedAatJ :datetime t. olumn : ontextAidJ :integer t. olumn :pro-e tAidJ :integer end end def "elf.down dropAtable :a tion" end end

Com isso6 = temos a#ora o su"iciente em nosso banco aplicao. .m recurso muito Ptil

a os para trabalhar um pouco em nossa

o Rails J o console6 que serve tanto para e0perimentar com as classes e outras "un&es Pteis e teste e manuteno

a os

como para e0ecutar uma sJrie

a aplicao. Para acessar o

controle6 use o se#uinte coman oA

ronaldo@minerva:~/tmp/gtd$ " ript/ on"ole Doading development environment. ..

A e0emplo

e um console

e coman o

o D+- ou

o pr<prio (,-DL6 o console

o Rails permite que voc@

insira um coman o e ve=a seus resulta os ime iatamenteA Por e0emploA

.. 4ontext. reate%:name !. H@;omeH( !. ?K4ontext:'xbR$fbb3 @newAre ord!fal"eJ @error"!?KL tive2e ord::1rror":'xbR$ f**8 @ba"e!?K4ontext:'xbR$fbb3 ....J @error"!ST.J @attribute"!SQnameQ!.Q@;omeQJ QidQ!.1T.

+ coman o acima cria e salva um novo conte0to6 receben o como parLmetro o nome

o mesmo6

escrito

por seu Pnico atributo. + resulta o6 visto lo#o epois o coman o6 J uma representao te0tual a classe. :o os ob=etos em Rub,6 e isso inclui representao te0tual. Ba maior parte es e nPmeros inteiros a classe comple0as6 possuem uma

os casos6 o Rub, #era uma representao te0tual automtica para

classes que no especi"icam a sua pr<pria representao e J isso o que voc@ est ven o acima. /m uma aplicao6 voc@ provavelmente precisar criar um ob=eto e manipul;lo antes e salv;lo. ?sso

*$

tambJm J possIvel6 como emonstra o abai0oA

.. ontext ! 4ontext.new !. ?K4ontext:'xbRR81bd' @newAre ord!trueJ @attribute"!SQnameQ!.nilT. .. ontext.name ! H@0or#H !. Q@0or#Q .. ontext."ave !. true

Bo e0emplo acima6 o ob=eto J cria o6 uma e suas proprie a e J atribuI a e epois isso o ob=eto J salvo. A persist@ncia e a os s< ocorre na invocao o mJto o sa!e. +utras opera&es so possIveisA

.. 4ontext.find%:all( !. )?K4ontext:'xbR*eR*d$ @attribute"!SQnameQ!.Q@;omeQJ QidQ!.Q1QT.J ?K4ontext:'xbR*eR*68 @attribute"!SQnameQ!.Q@0or#QJ QidQ!.Q&QT.+ .. 4ontext.find%&( !. ?K4ontext:'xbR*e&3&8 @attribute"!SQnameQ!.Q@0or#QJ QidQ!.Q&QT. .. 4ontext.find%:fir"tJ : ondition" !. )Hname li#e UHJ H@;omeH+( !. ?K4ontext:'xbR*d*b @attribute"!SQnameQ!.Q@;omeQJ QidQ!.Q1QT.

A primeira chama a acima retorna to os os re#istros correspon ente aos conte0tos. )emos que o resulta o J um arra,6 elimita o por 56. A se#un a chama a6 por sua ve>6 retorna o ob=eto especi"ica o pelo i passa o6 ou se=a6 por sua chave primria surro#a a. + terceiro mJto o6 por "im6 retorna o primeiro re#istro satis"a>en o as con i&es passa as. + mJto o find possui vrios outros parLmetros que servem para #erar queries comple0as sem es"oro6 or enan o o resulta o6 limitan o a quanti a e e itens retorna os6 e6 para usos mais avana os6 crian o

=oins automaticamente. )eremos e0emplos e0tensos isso mais a iante.


A so"isticao as classes #era as pelo ActiveRecor se esten e ao ponto a criao e mJto os

automticos para vrias situa&es. Al#umas

elas e0ploraremos

epois6 mas vale a pena notar aqui pelo

menos uma elasA mJto os e busca e criao automticos. Por e0emplo6 J possIvel e0ecutar o coman o abai0o para encontrar um conte0to pelo seu nomeA

.. 4ontext.findAbyAname%H@;omeH( !. ?K4ontext:'xbR* dfb8 @attribute"!SQnameQ!.Q@;omeQJ QidQ!.Q1QT.

+ mJto o find0by0name no e0istia atJ ser chama o. ?sso po e ser visto veri"ican o a e0ist@ncia o mJto o6 usan o respond0to?6 que J um mJto o presente em to as as classes Rub, e6 ao receber um sImbolo que especi"ica o nome o mJto o a ser testa o6 evolve uma valor in ican o se a classe suporta o mJto o ou
*1

noA

.. 4ontext.re"pondAtoU%:findAbyAname( !. fal"e .. 4ontext.findAbyAname%H@;omeH( !. ?K4ontext:'xbR6*f' $ @attribute"!SQnameQ!.Q@;omeQJ QidQ!.Q1QT.

Como J "cil perceber6 a classe no possui aquele mJto o atJ que ele se=a invoca o. .ma classe Rails aceita combina&es quaisquer mJto os. e seus atributos e

a os e

e al#umas opera&es para #erar esse tipo

.m e0emplo J find0or0create0by0name6 que procuraria um re#istro e o criaria caso no "osse encontra o6 com o nome passa o como parLmetro. -e a classe possuir mais atributos6 po erIamos muito bem usar al#o como find0or0create0by0name0and0description ou ain a find0by0description0and0completed0at. V claro que se usarmos isso para to as as chama as6 teremos mJto os com nomes absur amente lon#os como find0or0create0by0description0and0created0at0and0completed0at0and0done /que "icariam bem melhor como chama as separa as usan o con i&es por quest&es e le#ibili a e. + que estamos "a>en o aqui no console J basicamente o que "aremos em uma aplicao no que tan#e M manipulao e a os. Como voc@ po e ver6 na maior parte os casos6 o Rails no e0i#e que o as cenas6 com to a e"ici@ncia o mJto o esenvolve or escreva c< i#o -DL6 #eran o o c< i#o necessrio por trs possIvel. / caso se=a necessrio6 h ain a find6 que permitem a insero e "ra#mentos

uas possili a esA usar parLmetros mais avana os

e -DL em uma operao qualquerK ou ain a6 usar mJto os

como find0by0sql que permitem um e0ecuo ireta no banco com inte#rao plena com o Rails. .sar as "acili a es o Rails no si#ni"ica que o esenvolve or no precisa conhecer -DLK ao contrrio6 o o pr<prio Rails como para to as outras

conhecimento J "un amental6 tanto para evitar problemas no uso tare"as que e0istem alJm o Rails.

A#ora que = trabalhamos um pouco com o mo elo e a os6 vamos passar para a aplicao em si.

MVC
Como menciona o anteriormente6 o Rails utili>a o a estratJ#ia ()C. A parte correspon ente ao (o el e0iste nas classes e a os e J implementa a pelo ActiveRecor . .m se#un o componente o Rails6 o

ActionPac86 implementa o ) e o C que so respectivamente )ieG e Controller.


.m controller J uma classe responsvel por receber as requisi&es "eitas pela aplicao e e0ecutar as a&es necessrias para aten er essas requisi&es. /ssas a&es6 ao serem e0ecuta as6 provavelmente causaro mu anas no banco que sero e"etua as6 por sua ve>6 por uma ou mais classes e a os.

**

7inalmente6 o resulta o ser e0ibi o atravJs

e uma vieG6 que ser retorna a ao usurio na "orma

4:(L6 ima#ens6 9(L6 ou qualquer outra saI a aceitvel a aplicao. As tr@s partes a estratJ#ia ()C so in epen entes no Rails como everiam ser em qualquer boa

implementao as mesmas. Dualquer mo elo e a os po e ser utili>a o in epen entemente6 inclusive em

scripts que no tem a ver com a aplicao Eeb em si6 como6 por e0emplo6 tare"as a#en a as. +s controllers
tambJm so in epen entes e po em ser usa o para simplesmente e"etuar a&es que nem mesmo retornam

vieGs6 atuali>an o somente o banco ou


certa "orma6 a parte mais

isparan o outro processo qualquer no servi or. As vieGs so6

epen ente = que6 embora po en o ser utili>a as separa amente6 no "a>em

muito senti o sem utili>arem a os #era os por mo elos e a os e controllers. Para i enti"icar qual controller ser responsvel por aten er uma Rails utili>a uma mecanismo e roteamento etermina a solicitao a aplicao6 o e con"i#ura&es

e requisi&es automtico que no necessita

comple0as6 mas que po e tambJm ser customi>a o e acor o com as necessi a es e ca a aplicao. A re#ra principal entro a classe e i e roteamento no Rails "orma .RLs se#un o o pa ro /controller/action/id6 on e J um parLmetro opcional passa o para i enti"icar um ob=eto qualquer sobre o qual a ito anteriormente6 esse pa ro po e ser mo i"ica o e veremos mais sobre isso

controller J a classe responsvel por aten er a requisio especi"ica a por aquela .RL6 action J um mJto o
ao ser e"etua a. Como a iante no tutorial.

O PRIMEIRO CONTROLLER
)amos comear crian o um controller para li ar com a p#ina inicial e nossa aplicao. Para #erar um

controller6 usamos o coman o abai0oA

ronaldo@minerva:~/tmp/gtd$ " ript/generate ontroller ,ome exi"t" app/ ontroller"/ exi"t" app/,elper"/ reate app/view"/,ome exi"t" te"t/fun tional/ reate app/ ontroller"/,omeA ontroller.rb reate te"t/fun tional/,omeA ontrollerAte"t.rb reate app/,elper"/,omeA,elper.rb

+ nome passa o para o coman o J home6 que ser usa o para compor to os os arquivos #era os pelo mesmo. Da mesma "orma que nos mo elos e a os6 o Rails cria unit tests para a classe #era a6 que po em ser

e0ecuta os com o coman o ra3e/tests. /sse coman o ro a to os os unit tests presentes na aplicao e qualquer boa aplicao esenvolvi a se#un o a meto olo#ia /0treme Pro#rammin# "a> uso e0tensivo essa tJcnica. )eremos esse assunto em mais etalhes em uma outra seo e nosso tutorial. -e voc@ acessar a .RL esse controller a#ora6 voc@ vai receber a se#uinte telaA

*'

Repare que6 nesse caso6 eu in"ormei somente /controller/ como a .RL6 sem passar nem a parte correspon ente a uma ao ou a um i . Besse caso6 o Rails assume que estamos invocan o a ao in e0 sem i . /sse J um mais e0emplo e conveno ao invJs e con"i#urao. Ao invJs e ter sempre que especi"icar uma ao pa ro em al#um lu#ar6 o Rails convenciona que a ao pa ro J in e06 poupan o o esenvolve or sem a"etar a aplicao. )amos olhar o arquivo app/controllers/home0controller.rb #era o por nosso coman o. Como = mencionamos6 o Rails se#ue uma estrutura "i0a Arquivos relaciona os ao banco vo em no relaciona o a ()C vai em app. Dentro e iret<rios6 poupan o mais uma ve> o esenvolve or. iret<rio db6 arquivos e con"i#urao em config e tu o iret<rios que contJm mais partes

e app temos vrios outros

especI"icas a aplicao. /m al#uns casos6 o Rails tambJm a iciona um su"i0o ao arquivo6 evitan o colis&es e nomes e problemas estranhos na aplicao6 como J o caso aqui. + arquivo o controller cria o contJm o se#uinteA

la"" ;ome4ontroller K Lppli ation4ontroller end

A classe .ome7ontroller

e"ine quem que ir respon er a requisi&es pa ro em Zhome. /la her a e"ini a no arquivo application.rb6 no mesmo

classe -pplication7ontroller6 que est

iret<rio. -en o isponIvel nos

assim6 qualquer mJto o cria o na classe -pplication7ontroller estar automaticamente

controllers #era os para a aplicao.


+ uso e herana serve mais uma ve> para bene"iciar o esenvolve or que po e utili>ar um mo elo mental

"amiliar para trabalhar sua aplicao6 um mo elo que J ao mesmo tempo simples e po eroso.

*4

Para criarmos a ao in e06 basta a icionarmos um mJto o M classeA

la"" ;ome4ontroller K Lppli ation4ontroller def index end end

+ princIpio que usamos acima J comum a tu o em Rails. 3asicamente tu o o que "a>emos em uma aplicao usan o o mesmo consiste em e0ten er al#uma classe por meio a a io e mJto os customi>a os. Recarre#an o a p#ina no nave#a or6 "icamos com o se#uinteA

)amos que6

essa ve>6 o Rails i enti"icou a ao a ser e0ecuta a6 mas6 como a aplicao no especi"icou

nenhum retorno6 houve um erro. ?sso aconteceu porque o Rails tentou aplicar automaticamente uma vieG para aquela ao o controller. Como a vieG ain a no e0iste6 temos o erro. Antes e nos aventurarmos em uma vieG usan o o mecanismo e templates o Rails6 vamos retornar al#um te0to por contra pr<priaA

la"" ;ome4ontroller K Lppli ation4ontroller def index render :text !. Q:lVWQ end end

+ mJto o render6 epen e

isponIvel para qualquer controller ou vieG6 #era saI a na aplicao6 saI a esta que

e seus parLmetros. Bo caso acima6 estamos ren eri>an o te0to puro6 como in ica o pelo
*5

parLmetro text. Bossa p#ina a#ora "icaria assimA

:emos a nossa primeira saI a em uma aplicao Rails. Como escrever manualmente to a a saI a no J o que queremos6 vamos criar a nossa primeira vieG. Para isso6 criamos o arquivo app/!iews/home/index.rhtml. A e0tenso .rhtml in ica que esse arquivo contJm 4:(L e c< i#o Rub,. .ma outra e0tenso possIvel seria .r=s para #erar retorno em Qava-cript6 comumente utili>a o em aplica&es A=a0. 4 ain a .r0ml6 para #erar saI a em 9(L. +utros mecanismos e template po em usar outras e0tens&es6 = que o Rails po e ser con"i#ura o para outros mecanismos alternativos. Por hora6 usaremos a lin#ua#em e templates pa ro o Rails. )amos criar o se#uinte arquivo6 entoA

Kp.:lVJ mundoWK/p.

-e recarre#amos a p#ina6 notaremos que na a mu ou. ?sso acontece porque estamos usan o render/ iretamente. Besse caso6 o Rails etecta que al#uma saI a = "oi #era a e no tenta #erar outra. 3asta6 ento6 remover a chama a a render/mJto o index6 voltan o o arquivo aA

la"" ;ome4ontroller K Lppli ation4ontroller def index end

*1

end

A#ora6 recarre#an o a p#ina6 temosA

-em que ha=a necessi a e

e especi"icar qualquer coisa6 o Rails est usan o o arquivo a equa o. )e=a que e"inimos um mJto o no mesmo6 e criamos um esses a

no con"i#uramos qualquer coisa. Criamos um controller6 arquivos representa uma ca eia aplicao "a> isso ou aquilo. Dualquer outra ao que "osse cria a seria associa o a um nome e arquivo entro entro

arquivo que contJm o que queremos que se=a retorna o por aquele mJto o. A simples e0ist@ncia

e e0ecuo sem que precisamos nos preocupar com que parte

esse controller se#uiria o mesmo pa ro. + nome e um iret<rio em app/!iews cu=o nome seria o

a ao

o pr<prio

controller. + Rails tambJm J inteli#ente ao ponto e respon er a uma ao mesmo que o mJto o no e0ista6
es e que a vieG este=a presente no iret<rio correto.

LAYOUTS
Para "acilitar o esenvolvimento a parte visual e uma aplicao6 o Rails possui um conceito enomina o

la,outs.
Ba maioria as aplica&es Eeb6 as p#inas variam somente no seu conteP o principal6 possuin o e nave#ao em comum. +bviamente6 um "rameGor8 cu=o maior ob=etivo J esenvolve or no e0i#iria que o c< i#o para esses elementos tivesse que ser o

cabealhos6 ro apJs e barras aumentar a pro utivi a e inseri o automaticamente.

repeti o em ca a vieG. .m la,out "unciona como um arquivo rai>6 entro o qual o resulta o e uma vieG J

(ais uma ve> "avorecen o conveno ao invJs

e con"i#urao6 o Rails e"ine um arquivo pa ro e la,out


*!

que J usa o automaticamente por qualquer vieG a no ser que ha=a especi"icao em contrrio. + Rails tambJm J inteli#ente o bastante para somente usar um la,out em vieGs com a mesma e0tenso. + la,out pa ro para a aplicao "ica em um arquivo chama o application.rhtml6 app/!iews/layouts6 que no e0iste ain a. -e voc@ olhar a#ora o c< i#o #era o pela p#ina que criamos atJ o momento6 voc@ ver o se#uinteA entro o iret<rio

Como voc@ po e notar6 o estamos #eran o nenhum os elementos 4:(L #eralmente vistos em uma p#ina comum. )amos criar o arquivo application.rhtml no iret<rio especi"ica o6 com o se#uinte conteP oA

K,tml. K,ead. Ktitle.X<GK/title. K/,ead. Kbody. KY! yield Y. K/body. K/,tml.

:emos no arquivo acima6 o primeiro e0emplo e 8+=/objeto/+9/para retornar conteP o.

e uso

e c< i#o Rub,

entro

e uma vieG6

elimita o pelos

marca ores 8+ e +9. Aqueles "amiliari>a os com P4P e A-P reconhecero o estilo e marca ores6 com o uso

Bo caso acima6 o mJto o especial yield retorna o conteP o atual #era o pela ao6 se=a por meio

e uma

vieG ou usan o render

iretamente. + mJto o yield tem uma conotao especial no Rub,6 servin o para
*5

invocar o bloco associa o ao conte0to. ?nseri o em um la,out com seu conseqRente retorno e conteP o. A nossa p#ina recarre#a a a#ora "ica como mostra o abai0oA

o Rails6 o bloco

e"ine a e0ecuo

a ao6

Bo parece muita coisa6 mas6 olhan o o c< i#o6 voc@ ver o se#uinteA

V "cil perceber que o c< i#o aplicao.

o la,out "oi aplica o sobre o c< i#o

a vieG6 #eran o a saI a "inal

+ que precisamos "a>er a#ora J e0ten er o nosso la,out para incluir al#umas ameni a es. + nosso arquivo application.rhtml po eria ser mu a o para o se#uinteA
*2

K,tml. K,ead. Ktitle.X<GK/title. KY! "tyle",eetAlin#Atag QdefaultQ Y. K/,ead. Kbody. KY! yield Y. K/body. K/,tml.

+ mJto o stylesheet0lin30tag/recebe o nome mesma. + nosso c< i#o #era o a#ora "icou assimA

e uma st,lesheet como parLmetro e #era um lin8 para a

Bote que mais uma ve> o Rails assumiu um caminho pa ro. Besse caso6 o arquivo J servi o iretamente a rai> a aplicao6 que J o iret<rio public. )oc@ po e criar um arquivo chama o default.css no iret<rio public/stylesheets para a icion;lo M aplicao. .m e0emplo isso seriaA

body S font-family: ZerdanaJ LrialJ "an"-"erif5 font-"ize: 8'Y5 T

.ma coisa a manter em mente J que o la,out pa ro a aplicao no J6 e "orma al#uma6 o Pnico que po e ser #era o. )oc@ po e criar tantos la,outs quanto precisar6 colocan o;os no mesmo estaro acessIveis a to a aplicao. Para usar um la,out i"erente em um controler voc@ po eria "a>er al#o assimA iret<rio6 e on e

'$

la"" ;ome4ontroller K Lppli ation4ontroller layout Q,omeQ def index end end

+ la,out cu=o nome J home seria especi"ica o no arquivo app/!iews/layouts/home.rhtml6 com a mesma "uncionali a e o arquivo application.rhtml. .ma outra possibili a e que o Rails o"erence J sobrescrever um la,out para uma Pnica ao6 no mJto o render. .m e0emplo seriaA iretamente

la"" ;ome4ontroller K Lppli ation4ontroller layout Q,omeQ def index end def indexA"pe ial render :a tion !. Qli"tQJ :layout !. Q,omeA"pe ialQ end end

)oc@ po e tambJm suprimir inteiramente um la,out usan o :layout/=9/false. 7inalmente6 voc@ po e usar maneiras especI"icas e eterminar o la,out e uma p#ina. Por e0emploA

la"" ;ome4ontroller K Lppli ation4ontroller layout : ,oo"eAlayout def index end prote ted def ,oo"eAlayout % urrentAu"er.adminU( U Qadmini"trationQ : QnormalQ end end

Bo caso acima6

epen en o

o retorno

a chama a ao mJto o admin?6 a aplicao po eria usar o la,out

e"ini o no arquivo administration.rhtml/ou no arquivo normal.rhtml. Como po emos ver no h muitos limites para o que po e ser "eito.

'1

ROTEAMENTO
-e voc@ acessou a .RL rai> a aplicao6 voc@ ter nota o que ela no mu ou6 apesar o controller que criamos. ?sso acontece porque o Rails e"ine um arquivo index.html que serve como pa ro. -e removermos esse arquivo o iret<rio public4/"icaremos com a se#uinte p#inaA

/sse erro in ica que o Rails no conse#ue encontrar um roteamento que satis"aa a .RL que especi"icamos. Para resolvermos o problema6 vamos e itar o arquivo config/routes.rb6 que /sse arquivo contJm o se#uinte co i#oA e"ine esses roteamentos.

L tion4ontroller::2outing::2oute".draw do MmapM ? <,e priority i" ba"ed upon order of reation: fir"t

reated -. ,ig,e"t priority.

? >ample of regular route: ? map. onne t Hprodu t"/:idHJ : ontroller !. H atalogHJ :a tion !. HviewH ? Ieep in mind you an a""ign value" ot,er t,an : ontroller and :a tion ? >ample of named route: ? map.pur ,a"e Hprodu t"/:id/pur ,a"eHJ : ontroller !. H atalogHJ :a tion !. Hpur ,a"eH ? <,i" route an be invo#ed wit, pur ,a"eAurl%:id !. produ t.id( ? Fou an ,ave t,e root of your "ite routed by ,oo#ing up HH ? -- -u"t remember to delete publi /index.,tml. ? map. onne t HHJ : ontroller !. Qwel omeQ ? Lllow downloading 0eb >ervi e 0>GD a" a file wit, an exten"ion ? in"tead of a file named Hw"dlH map. onne t H: ontroller/"ervi e.w"dlHJ :a tion !. Hw"dlH ? 7n"tall t,e default route a" t,e lowe"t priority. map. onne t H: ontroller/:a tion/:idH end

Como os comentrios i>em6 esse arquivo e"ine roteamentos e .RLs para controllers. Ca a roteamento J

'*

e0amina o quan o uma .RL J processa a pelo Rails6 eclarao a e"inio e priori a e.

a primeira para a Pltima6 sen o a or em

Como voc@ po e ver no arquivo acima6 a .RL pa ro que mencionamos6 /controller/action/id J a Pltima a ser e"ini a6 sen o a aplica a caso no ha=a instru&es em contrrio. + roteamento no Rails J bem rico e os conceitos o mesmo mais a iante. Bo momento6 queremos apenas resolver o trabalharemos al#uns

problema a p#ina inicial. /ssa p#ina J representa a no arquivo acima pela linha abai0o6 comenta a no momento.

? map. onne t HHJ : ontroller !. Qwel omeQ

Para mapear o controller home como nossa p#ina inicial6 basta mo i"icar a linha para i>er o se#uinteA

map. onne t HHJ : ontroller !. Q,omeQ

A rota va>ia J um sin[nimo para a rota rai> e estamos

i>en o6 com o c< i#o acima que se a mesma "or

invoca a6 a requisio eve ser servi a pelo controller que e"inimos anteriormente. Bote a mistura que as aspas e aspas simples e aspas uas uplas nesse arquivo. Bo Rub,6 elas so relativamente e representar te0to nessa lin#ua#em. A i"erena J e variveis como veremos mais a iante no tutorial. /u ten o

intercambiveis e so apenas

as vrias "ormas

uplas permitem a interpolao

a "avorecer o uso e aspas uplas6 nas isso J uma opo pessoal. A#ora6 recarre#an o nossa p#ina inicial temosA

''

Bote que a#ora o mesmo controller serve

ois roteamentos. /ssa J apenas uma

as possibili a es mais

simples que esto isponIveis com o roteamento o Rails. A#ora que temos um conhecimento bsico e mo els6 controllers e vieGs6 po emos combinar o tr@s.

SCAFFOLDING
Para a=u ar na rpi a prototipao e aplica&es6 o Rails possui al#o chama o e sca""ol in#. + sca""ol in# prov@ uma estrutura bsica para opera&es CR.D SCreate6 Retrieve6 .p ate an apoiar o esenvolvimento atJ que voc@ insira a co i"icao necessria. Para e0perimentar com isso e e0pan ir um pouco nossa aplicao6 vamos criar um novo controller6 que servir para a ministrar os nossos conte0tosA

DeleteT6 ou

se=a6 aquelas opera&es bsicas que temos na manipulao e a os6 #eran o inter"aces rpi as que po em

ronaldo@minerva:~/tmp/gtd$ " ript/generate ontroller ontext" exi"t" app/ ontroller"/ exi"t" app/,elper"/ reate app/view"/ ontext" exi"t" te"t/fun tional/ reate app/ ontroller"/ ontext"A ontroller.rb reate te"t/fun tional/ ontext"A ontrollerAte"t.rb reate app/,elper"/ ontext"A,elper.rb

?nicialmente6 esse controller J como o que criamos anteriormente6 para a home nenhuma ao prJ; e"ini a.

a aplicao6 e no possui

)amos e itar o seu arquivo6 em app/controllers/contexts0controller.rb4/acrescentan o uma linha c< i#oA

la"" 4ontext"4ontroller K Lppli ation4ontroller " affold : ontext end

A#ora6 acesse a .RL estiver usan oA

esse controller6

i#itan o http://localhost::"""/contexts no nave#a or que voc@

'4

-em nenhuma linha conte0tos.

e c< i#o alJm

a inseri a acima6 temos lista#em6 insero6 atuali>ao e remoo

Clique em BeG conte0t para e0perimentarA

Depois6 clican o em Create6 temosA

'5

/6 "inalmente6 clican o em -hoG6 vemosA

Bote6 que na tela acima6 o i com outros ob=etos.

o ob=eto = aparece na .RL. Besse caso J 5 porque eu = e0perimentara antes

+ sca""ol in# J muito Ptil na #erao e controllers bsicos e a ministrao para ar apoio M prototipao e ao inIcio o esenvolvimento6 principalmente para ca astros6 permitin o que o esenvolve or se "oque no que J mais importante para a aplicao. + inconveniente J que as a&es #era as so bem limita as e no po em ser e ita as ou tra u>i as.
'1

Para e0pan ir um pouco a "uncionali a e6 e0iste outra "orma "le0ibili a e maior na e io p#inas "inais. Para isso6 use o coman o abai0o:

e #erao

e sca""ol in# que permite uma

as p#inas #era as6 que po em6 inclusive6 ser utili>a as como base para as

ronaldo@minerva:~/tmp/gtd$ " ript/generate " affold ontext exi"t" app/ ontroller"/ exi"t" app/,elper"/ exi"t" app/view"/ ontext" exi"t" te"t/fun tional/ dependen y model exi"t" app/model"/ exi"t" te"t/unit/ exi"t" te"t/fixture"/ identi al app/model"/ ontext.rb identi al te"t/unit/ ontextAte"t.rb identi al te"t/fixture"/ ontext".yml reate app/view"/ ontext"/Aform.r,tml reate app/view"/ ontext"/li"t.r,tml reate app/view"/ ontext"/",ow.r,tml reate app/view"/ ontext"/new.r,tml reate app/view"/ ontext"/edit.r,tml overwrite app/ ontroller"/ ontext"A ontroller.rbU )Fna@+ y for e app/ ontroller"/ ontext"A ontroller.rb overwrite te"t/fun tional/ ontext"A ontrollerAte"t.rbU )Fna@+ y for e te"t/fun tional/ ontext"A ontrollerAte"t.rb identi al app/,elper"/ ontext"A,elper.rb reate app/view"/layout"/ ontext".r,tml reate publi /"tyle",eet"/" affold. ""

Bote que6 para a #erao

e um sca""ol

por esse coman o6 o nome

o mo elo

a os J que

eve ser

passa o como parLmetro6 e no o nome o controller. + Rails J capa> e erivar um o outro. /sse coman o #era a classe o mo elo e a os6 o controller e vieGs para ca a ao CR.D necessria. Bo

caso acima6 como o mo el = e0istia6 ele no "oi cria o6 e "oi necessrio sobrescrever al#uns arquivos. 4 uas coisas a serem nota as aqui. Primeiro6 o sca""ol isso6 o la,out ori#inal #erou o seu pr<prio la,out6 com sua pr<pria ele6 e a icionar a st,lesheet

st,lesheet. Por causa

a aplicao "oi per i o. .ma soluo aqui ser remover o

arquivo app/!iews/layouts/contexts.rhtml6 = que no precisamos limita as6 como veremos a iante. Abrin o o novo arquivo #era o o controller6 temos o se#uinteA

scaffold.css ao arquivo application.rhtml. -e#un o6 as vieGs cria as continuam ra>oavelmente

la"" 4ontext"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Hli"tH end

'!

? X1<" ",ould be "afe %"ee ,ttp://www.w3.org/&''1/tag/do /w,en<oO"eXet.,tml( verify :met,od !. :po"tJ :only !. ) :de"troyJ : reateJ :update +J :redire tAto !. S :a tion !. :li"t T def li"t @ ontextApage"J @ ontext" ! paginate : ontext"J :perApage !. 1' end def ",ow @ ontext ! 4ontext.find%param"):id+( end def new @ ontext ! 4ontext.new end def reate @ ontext ! 4ontext.new%param"): ontext+( if @ ontext."ave fla",):noti e+ ! H4ontext wa" "u e""fully redire tAto :a tion !. Hli"tH el"e render :a tion !. HnewH end end def edit @ ontext ! 4ontext.find%param"):id+( end def update @ ontext ! 4ontext.find%param"):id+( if @ ontext.updateAattribute"%param"): ontext+( fla",):noti e+ ! H4ontext wa" "u e""fully updated.H redire tAto :a tion !. H",owHJ :id !. @ ontext el"e render :a tion !. HeditH end end def de"troy 4ontext.find%param"):id+(.de"troy redire tAto :a tion !. Hli"tH end end

reated.H

+ resulta o "inal6 ao ser e0ecuta o6 J muito pareci o com o sen o os arquivos e #era os enquanto que6

o mJto o scaffold6 com a maior

i"erena

o mo o anterior6 as a&es eram

inamicamente cria as pelo

Rails. Al#umas ameni a es6 como pa#inao6 tambJm "oram intro u>i as. .ma consi erao eve ser "eita aquiA o sca""ol in# J apenas um apoio M prototipao. /le no eve ser

usa o como uma muleta6 #eran o p#inas para mo i"icao. -e voc@ quer a ministra&es prontas6 e0istem

plu#ins para o Rails que permitem a #erao e p#inas bem avana as. /sses plu#ins po em ser utili>a os
para criar a ministra&es prontas a e0emplo as #era as pelo D=an#o So "rameGor8 equivalente ao Rails e uma aplicao e no levam em para o P,thonT6 mas mesmo elas tem suas limita&es e in"le0ibili a es. A lio J sempre procurar o que J melhor para a sua aplicao. +s sca""ol in#s so uma viso muito linear contra inter"aces alternativas e melhor usabili a e. De qualquer "orma6 o sca""ol in# #era o J uma boa oportuni a e para ver o relacionamento entre

controllers6 vieGs e mo els. -e voc@ tomar uma ao qualquer como e0emplo6 ver que ela usa a classe e
'5

a os para o acesso ao banco e empacota os

a os recebi os em variveis "echa as que sero usa as por

uma vieG6 evitan o que o c< i#o e apresentao se misture com a l<#ica e ne#<cio. (esmo elementos o pr<prio controller6 como pa#inao6 so inclui os nessa iscriminao. )e=a a vieG e lista#em6 por e0emplo6 escrita no arquivo list.rhtml/no iret<rio app/!iews/contextsA

K,1.Di"ting

ontext"K/,1.

Ktable. Ktr. KY for olumn in 4ontext. ontentA olumn" Y. Kt,.KY! olumn.,umanAname Y.K/t,. KY end Y. K/tr. KY for ontext in @ ontext" Y. Ktr. KY for olumn in 4ontext. ontentA olumn" Y. Ktd.KY!, ontext."end% olumn.name( Y.K/td. KY end Y. Ktd.KY! lin#Ato H>,owHJ :a tion !. H",owHJ :id !. ontext Y.K/td. Ktd.KY! lin#Ato H1ditHJ :a tion !. HeditHJ :id !. ontext Y.K/td. Ktd.KY! lin#Ato HGe"troyHJ S :a tion !. Hde"troyHJ :id !. ontext TJ : onfirm !. HLre you "ureUHJ :po"t !. true Y.K/td. K/tr. KY end Y. K/table. KY! lin#Ato H=reviou" pageHJ S :page !. @ ontextApage". urrent.previou" T if @ ontextApage". urrent.previou" Y. KY! lin#Ato H8ext pageHJ S :page !. @ ontextApage". urrent.next T if @ ontextApage". urrent.next Y. Kbr /. KY! lin#Ato H8ew ontextHJ :a tion !. HnewH Y.

+ mJto o paginate6 usa o no controller escon e a comple0i a e a os6 ivi in o os itens retorna os pelo nPmero variveis que contJm6 respectivamente6 uma lista numerao p#inas. em "uncionamento6 embora o sca""ol

e acesso ao banco "a>en o a busca

os uas

e itens requeri os por p#ina e retornan o

as p#inas Sque po e ser usa a na vieG para #erar a e 1$ itens6 ver isso e

as mesmasT e os itens re"erentes Mquela p#ina. -e voc@ ca astrar mais

#era o se limite M nave#ao para "rente e para trs na lista

A vieG acima tambJm e0ibe uma comple0i a e maior6 utili>an o vrios mJto os para a #erao #erao a .RL6 que po em ser combina os e vrias "ormas. Por e0emploA

o seu

conteP o. Bota amente6 o mJto o lin30to que recebe como o te0to o lin8 e parLmetros a icionais para a

KY! lin#Ato : ontroller !. Q,omeQ Y. KY! lin#Ato : ontroller !. Q ontext"QJ :a tion !. QeditQJ :id !. & Y. KY! lin#Ato : ontroller !. QloginQJ :u"ing !. Q oo#ie"Q Y.

Bo primeiro caso acima6 o mJto o #era a .RL rai> para um controller6 que como vimos J mapea a para a ao index. Bo se#un o caso6 uma .RL completa J retorna a. / no terceiro6 um parLmetro usin# J a iciona o M requisio6 #eran o a se#uinte .RLA /login?using=coo3ies.
'2

+ mJto o lin30to possui vrias outras capaci a es entre as quais #erar con"irma&es em Qava-cript e criar

"orms para submisso con"ivel

e lin8s que mo i"icam

estrutivamente seus

a os6 como po e ser visto

nos pr<prios arquivos #ea os nesse sca""ol . .ma olha a na esclarecimento maior essas op&es.

ocumentao J recomen a a para um

.m outro conceito interessante apresenta o nesse sca""ol J o e partials SparciaisT6 que so "ra#mentos e p#inas que po em ser compartilha os entre vieGs6 a mesma "orma que um la,out po e usar vrias vieGs. )e=a6 por e0emplo6 a relao entre os ois arquivos abai0oA Primeiro6 a vieG para criao e um novo re#istroA

K,1.8ew

ontextK/,1.

KY! "tartAformAtag :a tion !. H reateH Y. KY! render :partial !. HformH Y. KY! "ubmitAtag Q4reateQ Y. KY! endAformAtag Y. KY! lin#Ato H/a #HJ :a tion !. Hli"tH Y.

A#ora6 a vieG para e io e um re#istroA

K,1.1diting

ontextK/,1.

KY! "tartAformAtag :a tion !. HupdateHJ :id !. @ ontext Y. KY! render :partial !. HformH Y. KY! "ubmitAtag H1ditH Y. KY! endAformAtag Y. KY! lin#Ato H>,owHJ :a tion !. H",owHJ :id !. @ ontext Y. M KY! lin#Ato H/a #HJ :a tion !. Hli"tH Y.

Bote que o c< i#o #era o J muito pareci o S e "ato os ois arquivos e suas a&es relaciona as po eriam ser combina os em um Pnico ponto e acessoT e em ambos os arquivos h uma chama a ao mJto o render6 iret<rio. Arquivos que o arquivo J usan o um partial. /sse partial se encontra no arquivo/ 0form.rhtml6 no mesmo simplesA

e"inem partials sempre comeam com Y para especi"icar que so "ra#mentos. + conteP o

KY! errorAme""age"Afor H ontextH Y. KW--)form: ontext+--. Kp.Klabel for!Q ontextAnameQ.8ameK/label.Kbr/. KY! textAfield H ontextHJ HnameH Y.K/p. KW--)eoform: ontext+--.

Besse caso6 a parte o "ormulrio que J comum tanta M insero e um conte0to quanto M sua e io.

4$

Partials so uma as #ran es "acili a es o Rails6 sen o utili>a os principalmente em aplica&es A=a0 para
#erar somente os "ra#mentos o c< i#o necessrios para atuali>a&es e partes e uma p#ina. 4o=e6 com o uso o templates RQ-6 eles se tornaram ain a mais importantes. -e voc@ utili>ar o sca""ol #era o6 ver que o c< i#o J um pouco mais poli o6 com mensa#ens i"erena o que po eria ser "eito com uma Pnica linha e que sca""ol s so utJis6 mas no e sucesso e

pa#inao6 mas com pouco

e c< i#o6 como visto evem se tornar uma o Rails #eram

anteriormente. Por isso6 a observao anterior re#ra na aplicao. .m #ran e e0emplo as tabelas possibili a e e customi>ao. e lista#ens6 "a>en o invoca&es

as limita&es J o mo o como os sca""ol s bsicos iretas aos atributos

e um ob=eto em um loop com pouca

)e=a o "ra#mento e c< i#o abai0o6 proveniente a vieG index.rhtmlA

Ktr. KY for olumn in 4ontext. ontentA olumn" Y. Kt,.KY! olumn.,umanAname Y.K/t,. KY end Y. K/tr.

+s cabealhos mo elo pr<prios

a tabela

e lista#em so #era os "a>en o uma iterao sobre as colunas

e conteP o e

e a os em questo6 que no incluem colunas avana as e relacionamento e nem so capa>es e e colunas que contenham valores booleanos6 enumera os e tipos a os essas o banco. AlJm isso6 o mJto o human0name J volta o para o i ioma in#l@s e embora e0ista a e plu#ins e outros mJto os6 as limita&es e l<#ica na aplicao6

"a>er a tra uo a equa a possibili a e

e a apt;lo para outro i ioma por meio

tJcnicas so lo#o aparentes e6 se cui a o no "or toma o6 po em levar a problemas tornan o a mesma esnecessariamente comple0a e violan o os princIpios bsicos quais o Rails "oi construI o.

e simplici a e sobre os

Aproveitan o momentaneamente o c< i#o #era o6 vamos avanar um pouco em nossa aplicao6 "a>en o uso e mais uma caracterIstica no Rails.

VALIDAES
)ali a&es6 como o pr<prio nome in ica6 so um mo o e #arantir a inte#ri a e os a os em uma aplicao. + mo elo e vali a&es que o Rails "ornece J bastante completo e po e ser "acilmente e0pan i o pelo esenvolve or caso ele necessite e al#o no "orneci o por pa ro nas bibliotecas. Bo caso a nossa classe e a os inicial6 precisamos vali ar pelo menos o "ato o usurio ter in"orma o o

nome o conte0to ao ca astr;lo. Para isso6 vamos abrir o arquivo vali ao simplesA a classe6 que est em app/model/context.rb6 e e it;lo6 inserin o uma

41

la"" 4ontext K L tive2e ord::/a"e validate"Apre"en eAof :name end

-e voc@ tentar inserir a#ora um conte0to sem nome6 ver o se#uinteA

A menos que o usurio in"orme o nome o conte0to6 o Rails no permitir que o ob=eto se=a salvo. Bote que a vali ao J "eita no mo elo e a os e re"leti a na vieG atravJs os mJto os a mesma. + mJto o error0messages0for recolhe to as as mensa#ens e erro #era as urante uma vali ao e #era os itens e "ormulrio

o 4:(L necessrio para e0ibi;las6 que6 no caso acima6 ain a J "ormata o pela st,lesheet scaffold.css/ cria a anteriormente. Da mesma "orma6 os mJto os responsveis pela #erao Scomo text0field6 text0area6 select e datetime0select6 entre outrosT so capa>es campo a que se re"erem no "alhou em al#uma vali ao e encapsular a e0ibio in icao e erro. (Pltiplas vali a&es po em ser e"etua as em um mesmo campo. Por e0emplo6 para prevenir a insero nomes uplica os6 a se#uinte con io po eria ser coloca a na classeA e e veri"icar se o o campo em uma

4*

la"" 4ontext K L tive2e ord::/a"e validate"Apre"en eAof :name validate"Auni@uene""Aof :name end

+ resulta o seriaA

As mensa#ens

e erro #era as so pa roni>a as no pr<prio Rails6 mas po em ser customi>a as usan o o

se#uinte "ormatoA

la"" 4ontext K L tive2e ord::/a"e validate"Apre"en eAof :name validate"Auni@uene""Aof :nameJ :me""age !. Qmu"t be uni@ueQ end

Bote que o mJto o error0messages0for J volta o para o in#l@s6 "orman o "rases que "a>em mais senti o nesse i ioma6 enquanto o nosso portu#u@s pre"ere "rases mais elabora as. V "acil substituir o mJto o acima por uma implementao mais interessante a iante6 em outra seo o tutorial.
4'

o mesmo que aten a ao portu#u@s e como veremos mais

.m Pltimo passo seria atuali>ar esse sca""ol se#uinteA

para usar o la,out que criamos. Para isso6 remova o arquivo iret<rio app/!iews/layoutsT para o

contexts.rhtml e atuali>e o arquivo application.rhtml Sambos no

K,tml. K,ead. Ktitle.X<GK/title. KY! "tyle",eetAlin#Atag QdefaultQ Y. KY! "tyle",eetAlin#Atag Q" affoldQ Y. K/,ead. Kbody. KY! yield Y. K/body. K/,tml.

A mu ana no J #ran e6 mas si#ni"ica que nosso sca""ol a#ora usa o la,out a aplicao6 receben o to as as mo i"ica&es provenientes o mesmo. Cabe uma nota aqui sobre as a&es #era as no sca""ol e6 por e0tenso6 qualquer outra ao a ser cria a em uma aplicao. .m movimento entro a comuni a e o Rails ho=e J o uso e mJto os R/-:6 que representam uma

interpretao e um con=unto e pa r&es e "iloso"ias e esenvolvimento Eeb. /sses mJto os usam verbos 4::P mais especI"icos como P.: e D/L/:/ para e"etuar suas a&es6 ao invJs e usar somente os usuais %/: e P+-:. A pr<0ima verso o Rails6 ao que tu o in ica6 vir com um suporte bem "orte para esse tipo e uso. + presente tutorial no entrar nesses etalhes sobre isso6 mas ei0o ao leitor al#uns recursos para que ele possa pesquisar mais sobre o assuntoA http://www.xml.com/pub/a/;""</##/";/rest'on'rails.html http://pe=ra.barelyenough.org/blog/;"">/":/another'rest'controller'for'rails/ http://www.agilewebde!elopment.com/plugins/simplyrestful A#ora que vimos com o bsico "unciona no Rails6 po emos partir para tentar a nossa pr<pria implementao6 apren en o mais sobre com as coisas "uncionam.

UM SEGUNDO CONTROLLER
)amos criar o ca astro e pro=etosHque tambJm J bem simplesH e "orma mais manual para enten ermos a os. Para "acilitar6 vamos combinar a criao e e io e um como uma aplicao comum processa seus re#istro em uma Pnica ao. + primeiro passo J atuali>ar o mo elo e a os para e"etuar vali a&es. Bo caso no nosso mo elo e a os
44

para pro=etos Sque est no arquivo app/models/pro%ect.rbT6 precisamos A classe "icaria6 assumin o que o atributo description J opcional6 assimA

e vali a&es i#ualmente simples.

la"" =ro-e t K L tive2e ord::/a"e validate"Apre"en eAof :name validate"Auni@uene""Aof :name end

.m se#un o passo J #erar um controller para li ar com as requisi&es relaciona as ao ca astro e pro=etos. Dessa ve>6 vamos usar o coman o automaticamente. 3asicamente6 queremos as a&es in e06 list6 e it e elete. A ao in e0 e0iste para no precisarmos e uma re#ra e roteamento e0plIcita mas ser meramente uma invocao a ao list. / ao e it resumir to as as a&es e criao e insero6 simplican o o c< i#o. + coman o para #erar controller J o se#uinteA e #erao o controllers especi"ican o = as a&es que ese=amos criar

ronaldo@minerva:~/tmp/gtd$ " ript/generate ontroller pro-e t" index li"t edit delete exi"t" app/ ontroller"/ exi"t" app/,elper"/ reate app/view"/pro-e t" exi"t" te"t/fun tional/ reate app/ ontroller"/pro-e t"A ontroller.rb reate te"t/fun tional/pro-e t"A ontrollerAte"t.rb reate app/,elper"/pro-e t"A,elper.rb reate app/view"/pro-e t"/index.r,tml reate app/view"/pro-e t"/li"t.r,tml reate app/view"/pro-e t"/edit.r,tml reate app/view"/pro-e t"/delete.r,tml

Como voc@ po e ver6 os arquivos

as vieGs "oram automaticamente cria os6 e se voc@ abrir o arquivo

controller em si Sapp/controllers/pro%ects0controller.rbT voc@ ver o esqueleto que "oi #era oA

la"" =ro-e t"4ontroller K Lppli ation4ontroller def index end def li"t end def edit end def delete end end

?nvocan o o controller em seu nave#a or6 voc@ ver o se#uinteA

45

B<s a#ora temos um controller que respon e per"eitamente Ms nossas a&es6 com vieGs = associa as6 prontas para o uso. Como a ao in e0 J somente uma invocao simplesA a ao list6 po emos remover o arquivo a vieG a mesma

que est em app/!iews/pro%ects/index.rhtml /e comear a e itar as a&es. + mJto o in e0 J muito

la"" =ro-e t"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t end def edit end def delete end end

+ que essas uas linhas nos i>em soA primeiro6 invoque o mJto o list6 e epois ren eri>e a vieG a ao

list. (esmo representan o uma ao em si6 list no passa


m#ica

e um mJto o comum

a classe. V somente a e vieGs

o Rails que o torna uma ao6 e6 sen o assim6 ele po e ser invoca o normalmente6 como qualquer e i enti"icao

outra mJto o. A se#un a linha J necessria porque o mecanismo automtico

procuraria a vieG relaciona a a index e no a list. Precisamos6 ento6 e0plicitar a que ser usa a pela
41

aplicao. Antes e construirmos a ao list6 precisamos provi enciar um mo o e inserirmos re#istros o banco. Para isso6 precisamos criar a nossa ao e it. :emos uas situa&es possIveisA ou o usurio est crian o um novo re#istro6 ou ele est atuali>an o um re#istro e0istente. +bviamente6 a Pnica um ob=eto J e0ibir o "ormulrio o mesmo para preenchimento. Como a&es relaciona as somente a e0ibio #eralmente so associa as ao mJto o 4::P %/: enquanto a&es que mo i"icam a os e epen em e "ormulrios so invoca as a partir o mJto o P+-:6 vamos usar essa i"erenciao para i enti"icar se estamos salvan o o ob=eto ou somente e0ibin o o "ormulrio para e io. / mais6 vamos usar a e0ist@ncia ou no o parLmetro i para i enti"icar se estamos li an o com um novo ob=eto ou com um ob=eto = e0istente. A primeira verso o nosso mJto o "icaria assim6 entoA i"erena entre esses ois mJto os J a e0ist@ncia ou no o ob=eto. / a primeira coisa a ser "eita tanto na criao quanto na e io e

la"" =ro-e t"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t end def edit if param"):id+ @pro-e t ! =ro-e t.find%param"):id+( el"e @pro-e t ! =ro-e t.new end if re@ue"t.po"tU end end def delete end end

+ primeiro teste o mJto o veri"ica se um parLmetro i retornar ver a eiro. -e voc@ quiser =o#ar pelo la o params5:id6.nil?6 com uma inverso

"oi passa o. Bo Rub,6 J possIvel testar a e0ist@ncia

como na lin#ua#em C. -e o ob=eto "or nuloHou nil em Rub,Ho teste retornar "also. Caso contrrio6 a le#ilibi a e6 a linha po eria ser converti a para if/ as con i&es. +u voc@ po e usar unless/params5:id6.nil? /sem

inverter as con i&es6 = que essa eclarao testa o contrrio e uma eclarao if. A verso o teste que usamos acima J um pouquinho mais e"iciente6 mas no o su"iciente para "a>er

qualquer i"erena #eral a aplicao e voc@ po e pre"erir a le#ibili a e maior. Bo c< i#o acima6 epen en o a e0ist@ncia ou no o parLmetro6 tentamos carre#ar o ob=eto o banco ou

criar um novo ob=eto6 preparan o o caminho para a nossa vieG.

4!

+ se#un o teste

o mJto o veri"ica se estamos receben o uma requisio P+-:. Como mencionamos

anteriormente6 J isso que vamos usar para saber se estamos simplesmente e0ibin o o "ormulrio Sse=a va>io ou noT6 ou se est na hora e persistir o ob=eto para o banco. (ais M "rente colocaremos esse c< i#o. Caso voc@ ache que o nome e it para esse mJto o J meio en#anoso quan o um novo re#istro est sen o cria o6 voc@ po e usar re#ras eciso que e roteamento #enJricas para especi"icar que invoca&es a a&es chama as o que voc@ est "a>en o no momento. A ten @ncia com o uso e R/-:6

create6 up ate6 e save so re ireciona as para a mesma ao e it. -eparar ou no as suas a&es J um
epen e obviamente inclusive6 J e a&es bem especI"icas6 que respon em a somente um tipo e verbo 4::P. A#ora que o nosso mJto o comeou a tomar "orma6 precisamos e itar a vieG edit.html para e0ibir o nosso "ormulrio. + arquivo presente est assimA

K,1.=ro-e t"?editK/,1. Kp.9ind me in app/view"/pro-e t"/edit.r,tmlK/p.

Precisamos in icar ao usurio se estamos e itan o um re#istro e0istente ou a icionan o um novo re#istro no pr<prio cabealho a p#ina. Para isso po emos usar o se#uinte c< i#oA

K,1.KY if @pro-e t.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. =ro-e tK/,1.

Bote que estamos usan o a varivel ?pro%ect que criamos no mJto o edit. + ? in ica uma varivel instLncia6 que o Rails automaticamente propa#a para qualquer vieG sen o processa a a partir que a varivel "oi e"ini a. Ba linha acima6 estamos usan o o mJto o/new0record?6 presente em to as as classes e a os

a ao em

eriva as

o ActiveRecor para i enti"icar se estamos li an o com um novo re#istro ou com um re#istro = e0istente. /sse mJto o retorna ver a eiro enquanto a classe no "or salva pela primeira ve>. Com base nisso6 e0ibimos o nosso cabealho. -e voc@ ro ar a p#ina6 invocan o iretamente a .RL /pro%ects/edit6 ver que = temos al#o "uncionan oA

45

+bviamente6 se voc@ tentar usar um i re#istro no banco e a os.

qualquer voc@ ver um erro a menos que tenha inseri o aquele

+ pr<0imo passo a#ora J criar o "ormulrio e a os. Para isso6 vamos e itar a nossa vieGA

K,1.KY if @pro-e t.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. =ro-e tK/,1. KY! "tartAformAtag :a tion !. QeditQJ :id !. @pro-e t Y. KY! endAformAtag Y.

+ mJto o start0form0tag "unciona estamos usan o6 se=a novo ou no.

e maneira muito similar o mJto o lin30to6 e0plica o anteriormente. o ob=eto que

Bo caso acima6 estamos #era o um "ormulrio apontan o para a ao e it e passan o o i

Duas coisas so interessantes nesse chama aA primeiro6 o Rails J inteli#ente o bastante para perceber que voc@ est passan o o ob=eto como se "osse o seu i qualquer teste. + outro mJto o chama o6 end0form0tag6 simplesmente #era o "echamento o elemento form na p#ina. Com o cabealho um nome e um o nosso "ormulrio #era o6 po emos a#ora criar campos para e io. .m pro=eto possui escrio. + primeiro atributo J um te0to simples6 e uma linha somente6 enquanto o e #erar o c< i#o necessrio automaticamenteK se#un o6 sem que voc@ precise "a>er caso o ob=eto no tenha si o salvo6 o Rails suprimir automaticamente o i

se#un o J um te0to que po e ter mPltiplas linhas. / itan o o nosso arquivo6 teremos o se#uinteA

42

K,1.KY if @pro-e t.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. =ro-e tK/,1. KY! "tartAformAtag :a tion !. QeditQJ :id !. @pro-e t Y. Kp. Klabel for!Qpro-e tAnameQ.8ame:K/label.Kbr. KY! textAfield Qpro-e tQJ QnameQ Y. K/p. Kp. Klabel for!Qpro-e tAde" riptionQ.Ge" ription:K/label.Kbr. KY! textAarea Qpro-e tQJ Qde" riptionQJ :row" !. 5 Y. K/p. KY! endAformAtag Y.

/ssa mo i"icao nos o se#uinteA

+s mJto os text0field e text0area so responsveis pela #erao e

os elementos

e "ormulrio vistos

acima. + Rails possui e>enas esses mJto os6 capa>es e #erar vrias combina&es possIveis para os tipos a os suporta os automaticamente e permitir e0tens&es se voc@ precisar e al#o mais customi>a o. / voc@ sempre po e #erar o seu c< i#o manualmente em situa&es especiais. )e=a que ca a mJto o recebe um ob=eto e um atributo a ser #era o. Bo caso precisa usar o ? iretamenteA basta passar o nome que est sen o e0ecuta o. -e voc@ olhar o 4:(L #era o6 ver o se#uinteA esses mJto os6 voc@ no o controller

o ob=eto e o mJto o saber recuper;lo

5$

Kp. Klabel for!Qpro-e tAnameQ.8ame:K/label.Kbr. Kinput id!Qpro-e tAnameQ name!Qpro-e t)name+Q "ize!Q3'Q type!QtextQ /. K/p. Kp. Klabel for!Qpro-e tAde" riptionQ.Ge" ription:K/label.Kbr. Ktextarea ol"!Q$'Q id!Qpro-e tAde" riptionQ name!Qpro-e t)de" ription+Q row"!Q5Q.K/textarea. K/p.

)e=a que os mJto os #eram um "ormato similar

e elementos6 crian o atributos name e i

especI"icos para os a os

"acilitar a vi a o esenvolve or. + atributo i po e ser associa o a um elemento label como emonstra o e o atributo name J o que J envia o ao Rails6 #eran o automaticamente uma tabela hash submeti os pelo "ormulrio que a ao po e usar. Dentro e um controller voc@ ser capa> e usar params5:pro%ect6 para acessar iretamente essa tabela

hash6 como voc@ ver a iante.


+ pr<0imo passo6 a#ora6 J a icionar a&es para salvar ou cancelar a e io. Po erIamos ter al#o assimA

K,1.KY if @pro-e t.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. =ro-e tK/,1. KY! "tartAformAtag :a tion !. QeditQJ :id !. @pro-e t Y. Kp. Klabel for!Qpro-e tAnameQ.8ame:K/label.Kbr. KY! textAfield Qpro-e tQJ QnameQ Y. K/p. Kp. Klabel for!Qpro-e tAde" riptionQ.Ge" ription:K/label.Kbr. KY! textAarea Qpro-e tQJ Qde" riptionQJ :row" !. 5 Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQ Y. K/p. KY! endAformAtag Y.

+ "ormato acima J uma pre"er@ncia um esta o anterior. (ais

e muitas aplica&es Rails e re"lete o "ato

e que a ao para salvar escobrir qual boto "oi

everia ser submeti a pelo "ormulrio enquanto a ao

e cancelamento seria simplesmente um retorno a

o que isso6 o mJto o acima evita que tenhamos que e "orar uma mistura

pressiona o em nosso "ormulrio. /mbora o c< i#o para isso se=a bem simples6 repetI;lo em ca a "ormulrio se tornaria rapi amente te ioso6 alJm evitar a to o custo. /sse J um pa ro que voc@ ver repeti amente em aplica&es atuais e que "a> bastante senti o o ponto e vista e usabili a e. + resulta o seriaA e apresentao com l<#ica que queremos

51

:emos a#ora um "ormulrio completo "uncionan o. Precisamos simplesmente salvar o que ser submeti o. )oltan o ao nosso controller6 "icamos com o se#uinteA

la"" =ro-e t"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t end def edit if param"):id+ @pro-e t ! =ro-e t.find%param"):id+( el"e @pro-e t ! =ro-e t.new end if re@ue"t.po"tU @pro-e t.attribute" ! param"):pro-e t+ if @pro-e t."ave redire tAto :a tion !. Qli"tQ end end end def delete end end

5*

:o o ob=eto que representa uma classe representa uma coleo para preenchimento Rails na submisso as colunas

a os no Rails possui um atributo chama o attributes6 que a os #era os pelo

a tabela equivalentes. /sse atributo aceita receber uma tabela hash ireta no ob=eto. Ca a item

e seus valores. Como menciona o anteriormente6 J aqui que os o "ormulrio vem a calhar6 servin o para associao

e0istente em params5:pro%ect6 no c< i#o acima6 como6 por e0emplo6 params5:pro%ect65:name66 preencher seu item correspon ente sem necessi a e e c< i#o a icional. Continuan o o c< i#o6 tentamos salvar o ob=eto. -e isso tem sucesso Sou se=a6 se nenhuma vali ao "alhaT re irecionamos para a p#ina e lista#em. Caso contrrio6 e0ibimos o "ormulrio novamente. Besse caso6 note que o Rails usar a mesma vieG6 se#uin o o comportamento pa ro6 e"etivamente mostran o o "ormulrio preenchi o com os a os posta os. ?sso acontece porque os mJto os text0field e text0area Se os emaisT preenchem automaticamente os elementos e "ormulrio com os valores e0istentes no ob=eto que receberam. ?sso torna a nossa tare"a bem simples. -e voc@ tentar salvar um "ormulrio sem preencher na a6 ver o se#uinte a#oraA

Botamos que a vali ao est "uncionan o6 mas nenhum erro J e0ibi o. Para isso6 precisamos mo i"icao em nossa vieGA

a se#uinte

5'

K,1.KY if @pro-e t.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. =ro-e tK/,1. KY! errorAme""age"Afor Qpro-e tQ Y. KY! "tartAformAtag :a tion !. QeditQJ :id !. @pro-e t Y. Kp. Klabel for!Qpro-e tAnameQ.8ame:K/label.Kbr. KY! textAfield Qpro-e tQJ QnameQ Y. K/p. Kp. Klabel for!Qpro-e tAde" riptionQ.Ge" ription:K/label.Kbr. KY! textAarea Qpro-e tQJ Qde" riptionQJ :row" !. 5 Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p. KY! endAformAtag Y.

+ que nos A

54

-e voc@ salvar um ob=eto a#ora6 ver que somos re ireciona os para a ao list que ain a precisamos criar. .ma lista#em J al#o bem simples e queremos e0ibir6 inicialmente6 somente o nome vamos criar al#o bem bsicoA o pro=eto. Para isto6

K,1.=ro-e t"K/,1. Ktable border!Q1Q Ktr. Kt,.8ameK/t,. K/tr. K/table. ellpadding!Q5Q ell"pa ing!Q1Q.

?sso nos um tabela simples. A#ora6 queremos e0ibir os re#istros cria os. Precisamos6 obviamente6 buscar esses ob=etos no banco. (o i"ican o o controller "icamos com al#o assimA

la"" =ro-e t"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @pro-e t" ! =ro-e t.find :allJ :order !. QnameQ end def edit if param"):id+ @pro-e t ! =ro-e t.find%param"):id+( el"e @pro-e t ! =ro-e t.new end if re@ue"t.po"tU @pro-e t.attribute" ! param"):pro-e t+ if @pro-e t."ave redire tAto :a tion !. Qli"tQ end end end def delete end end

.m varivel chama a ?pro%ects receber uma lista

e to os pro=etos or ena os pelo atributo name. +

mJto o find6 = trata o anteriormente6 recebe como primeiro parLmetro uma especi"icao o que retornar ou um i especI"ico. Bo caso acima6 queremos to os re#istros SallT. + se#un o parLmetro6 nomea o6 recebe a especi"icao e or enao. .m etalhe a chama a acima. (uitas ve>es6 em c< i#o Rub,6 voc@ ver um seqR@ncia e uma tabela hash com Pltimo parLmetro e parLmetros

nomea os no "im e uma chama a. + Rub, no possui parLmetros nomea os em si6 mas J capa> e simular isso com o uso e um mJto o. Duan o um mJto o usa essa tJcnica6 o Rub, automaticamente permite que os parLmetros se=am eclara os e "orma livre6 pelo nome6 e

55

os combina no momento primeiro parLmetro

a chama a em uma tabela hash que J ento passa a como parLmetro. Assim6 o acima J um sImbolo e o se#un o parLmetro J uma tabela hash cu=o

o mJto o "in

Pnico elemento J um par e"ini o por um sImbolo e uma strin#. A#ora6 = po emos usar esses ob=etos em uma vieGA

K,1.=ro-e t"K/,1. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. K/tr. KY @pro-e t".ea , do Mpro-e tM Y.Ktable border!Q1Q Ktr. Ktd.KY! pro-e t.name Y.K/td. K/tr. KY end Y. K/table.

ellpadding!Q5Q

ell"pa ing!Q1Q.

Bo caso acima6 o mJto o find retorna um arra, que po e ou no conter itens. .ma coisa a manter em mente aqui J que6 para caso e uso esse mJto o6 o retorno po e ser i"erente. -e voc@ estiver usan o find/com/:first6 o retorno ser um ob=eto ou o valor nil. -e voc@ estiver passan o um

i especI"ico6 um ob=eto ser retorna o ou um erro ser #era o. Lembre;se isso sempre que usar o mJto o
em suas varia&es. As varia&es servem para cobrir as situa&es mais comuns6 e voc@ sempre po e escrever seus pr<prios mJto os usan o as combina&es acima para obter o resulta o que ese=a. Com ois pro=etos inseri os6 o resulta o JA

Po emos a#ora mo i"icar a nossa vieG para permitir al#umas a&es sobre esses ob=etos. Por e0emploA

51

K,1.=ro-e t"K/,1. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.L tion"K/t,. K/tr. KY @pro-e t".ea , do Mpro-e tM Y. Ktr. Ktd.KY! pro-e t.name Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. pro-e t Y. or KY! lin#Ato QGeleteQJ :a tion !. QdeleteQJ :id !. pro-e t Y. K/td. K/tr. KY end Y. K/table.

Como voc@ ever ter nota o pelas chama as a lin8Yto na vieG acima e em outros pontos o c< i#o = e0ibi o6 o Rails J capa> e erivar os elementos a uma .RL os parLmetros que esto sen o usa os no momento. + resulta o a aplicao a vieG acima J visto abai0oA

Clican o na e io e um os itens acima6 temosA

5!

Como J possIvel ver6 o cabealho e nosso controller.

a p#ina mu ou para in icar uma e io e os campos = vieram e re"inar al#uns aspectos

preenchi os. )oc@ = po e alterar ca a ob=eto sem problemas. Precisamos a#ora

Precisamos e um lin8 para criar um novo re#istro. ?sso J "acilmente conse#ui oA

K,1.=ro-e t"K/,1. Kp.KY! lin#Ato Q8ew =ro-e tQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.L tion"K/t,. K/tr. KY @pro-e t".ea , do Mpro-e tM Y. Ktr. Ktd.KY! pro-e t.name Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. pro-e t Y. or KY! lin#Ato QGeleteQJ :a tion !. QdeleteQJ :id !. pro-e t Y. K/td. K/tr. KY end Y. K/table.

.m os problemas em ei0ar que um re#istro se=a removi o com um simples invocao J que o usurio no tem como reverter a ao. Po emos a icionar um mInimo e proteo com a se#uinte alteraoA

55

K,1.=ro-e t"K/,1. Kp.KY! lin#Ato Q8ew =ro-e tQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.L tion"K/t,. K/tr. KY @pro-e t".ea , do Mpro-e tM Y. Ktr. Ktd.KY! pro-e t.name Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. pro-e t Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. pro-e t TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table.

Bote que6 por estamos usan o um terceiro parLmetro ao re or

o mJto o lin30to6 precisamos

e a icionar chaves

o se#un o para que o Rub, no e0era o seu comportamento pa ro e concatene to os os a chama a como o terceiro so

parLmetros livres em um s<. Bo caso acima6 tanto o se#un o parLmetro tabelas hash6 embora somente a se#un a este=a e0plicitamente in ica a. + resulta o pro=etoA

as mo i"ica&es acima J o se#uinte6 como po emos ver ao clicar na ao para remover o

A ao

elete tambJm po e ser prote#i a e acesso %/: iretos com o uso e outra caracterIstica o Rails
o sca""ol que "oi #era o anteriormente para o mo elo e

que J a trans"ormao e lin8s em "ormulrios caso a ao se=a bem simples. + resulta o visual no J muito interessante e voc@ po e observ;lo no c< i#o a os e conte0tos.

52

)amos a#ora inserir a ao para e0cluir re#istros6 que J bem simplesA

la"" =ro-e t"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @pro-e t" ! =ro-e t.find :allJ :order !. QnameQ end def edit if param"):id+ @pro-e t ! =ro-e t.find%param"):id+( el"e @pro-e t ! =ro-e t.new end if re@ue"t.po"tU @pro-e t.attribute" ! param"):pro-e t+ if @pro-e t."ave redire tAto :a tion !. Qli"tQ end end end def delete =ro-e t.find%param"):id+(.de"troy redire tAto :a tion !. Qli"tQ end end

Como essa ao no possui nenhuma vieG6 o arquivo #era o delete.rhtml tambJm po e ser e0cluI o. .ma outra alterao que po e ser "eita J a e0ibio vamos usar uma outra caracterIstica e sesso6 mas somente persistem e mensa#ens e a os para al#umas a&es. Para isso6

os Rails6 as variveis "lash. /ssas variveis so similares a variveis

e uma p#ina para outra. .ma ve> que a requisio para a qual "oram

propa#a as acaba6 elas so automaticamente removi as o conte0to e e0ecuo. )amos mo i"icar nosso controller mais uma ve>A

la"" =ro-e t"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @pro-e t" ! =ro-e t.find :allJ :order !. QnameQ end def edit if param"):id+ @pro-e t ! =ro-e t.find%param"):id+( el"e @pro-e t ! =ro-e t.new end if re@ue"t.po"tU

1$

@pro-e t.attribute" ! param"):pro-e t+ if @pro-e t."ave fla",):noti e+ ! Q<,e pro-e t wa" "u redire tAto :a tion !. Qli"tQ end end end def delete =ro-e t.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e pro-e t wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully "avedQ

e""fully deletedQ

Po emos a#ora usar essas variveis em nossa vieG para a ao list6 que J para on e as questo retornamA

uas a&es em

K,1.=ro-e t"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew =ro-e tQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.L tion"K/t,. K/tr. KY @pro-e t".ea , do Mpro-e tM Y. Ktr. Ktd.KY! pro-e t.name Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. pro-e t Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. pro-e t TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table.

.ma pequena observao que cabe aqui J o uso

e sImbolos ao invJs

e strin#s na re"er@ncia a tabelas uas "ormas e os

hash. -Imbolos so sempre uma "orma

e acesso mais interessante por apontarem sempre para uma Pnica

instLncia e po erem ser otimi>a os pelo interpreta or. + Rails #eralmente permite as mJto os e acesso e manter um pa ro em relao ao mesmo. ?sso "acilita a le#ibili a e

acesso para suas variveis internas representa as com tabelas hash6 mas J sempre bom escolher um evita o aparecimento e erros proveniente a mistura os ois tipos e acesso. + resulta o J o se#uinte6 ap<s uma ao e e ioA

a aplicao e

11

A varivel "lash\Anotice] est a p#ina.

isponIvel somente naquela requisio como voc@ po e veri"icar recarre#an o

EXTENDENDO UM MODELO DE DADOS


Al#o que po emos "a>er a#ora6 para aproveitar o nosso controller J e0ten er o nosso mo elo )amos i>er que precisamos saber se um pro=eto est ativo ou no. + nosso mo elo e esse atributo6 mas po emos #erar uma mi#rao para isso. e a os. a os no contJm

ronaldo@minerva:~/tmp/gtd$ " ript/generate migration addA"tatu"AtoApro-e t exi"t" db/migrate reate db/migrate/''$AaddA"tatu"AtoApro-e t.rb

/ssa J uma mi#rao um pouco

i"erente porque a iciona uma coluna a um mo elo

a os. / itan o o

arquivo a mi#rao6 terIamos al#o assimA

la"" Ldd>tatu"<o=ro-e t K L tive2e ord::Bigration def "elf.up addA olumn :pro-e t"J :a tiveJ :boolean =ro-e t.re"etA olumnAinformation =ro-e t.updateAall Qa tive ! 1Q end def "elf.down removeA olumn :pro-e t"J :a tive end end

Besse caso6 estamos a icionan o uma coluna e automaticamente atuali>an o para um valor que achamos

1*

mais in ica o. Como o nosso mo elo est sen o mo i"ica o6 precisamos usar o mJto o reset0column0information para que o Rails releia as tabelas e recarre#ue os mo elos ime iatamente. Ba ver a e6 isso no J estritamente necessrio pelo uso o mJto o update0all6 mas J interessante saber que esse uso po e ser necessrio em e -DL passa o como al#uns casos. + mJto o update0all/atuali>a to os os re#istros usan o o "ra#mento parLmetro.6 pulan o quaisquer vali a&es e0istentesHportanto6 use;o com cui a o. Ap<s ro ar o coman o ra8e db:migrate4 veremos o nosso banco atuali>a o completamente. Bote que6 nesse caso6 a mi#rao para um verso anterior simplesmente remove a coluna.

USANDO HELPERS
A#ora precisamos atuali>ar o nosso controller e nossas vieGs. + primeiro passo J atuali>ar a lista#em para e0ibir a situao o pro=eto. Para isso vamos utili>ar um recurso o Rails chama o e helpers.

4elpers so classes associa as a ca a controller que contJm "un&es utilitrias que so automaticamente
e0porta as para as vieGs associa as ao mesmo. Ca a controller tem o seu pr<prio helper e6 a e0emplo os

controllers6 to os os helpers her am mJto os


app/helpers/application0helper.rb. +lhan o no

e uma classe base6 que est iret<rio

e"ini a no arquivo

esse arquivo voc@ po e ver que para ca a

controller6 um helper = "oi #era o.


Precisamos e um mJto o que receba um valor booleano e retorne um representao humana a classe isso. Como

talve> precisemos usar esse mJto o em outras vieGs que no as presente no iret<rio app/helpers. :erIamos6 ento6 al#o assimA

e pro=etos6 seria mais

interessante inserir o mJto o no helper #lobal a aplicao6 mo i"ican o o arquivo application0helper.rb/

module Lppli ation;elper def ye"AorAnoU%value( value U QFe"Q : Q8oQ end end

+ mJto o yes0or0no? est a#ora nossa vieGA

isponIvel para qualquer vieG na aplicao. )amos us;lo6 mo i"ican o a

K,1.=ro-e t"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew =ro-e tQJ :a tion !. QeditQ Y.K/p.

1'

Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.L tiveK/t,. Kt,.L tion"K/t,. K/tr. KY @pro-e t".ea , do Mpro-e tM Y. Ktr. Ktd.KY! pro-e t.name Y.K/td. Ktd.KY! ye"AorAnoU%pro-e t.a tiveU( Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. pro-e t Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. pro-e t TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table.

Bote que po emos a#ora chamar o mJto o classe. .ma conveno especial

e"ini o no helper e tambJm que temos um novo atributo na

o Rails J que6 se um atributo representar um valor booleano6 voc@ po e e a os possuem campos booleanos nativos por pa ro. Bo caso

acrescentar um ponto e interro#ao ap<s o mJto o para que ele retorne ver a eiro ou "also iretamente. ?sso acontece porque nem to os bancos o (,-DL6 por e0emplo6 valores booleanos so representa os por campos inteiros conten o >ero ou um. + uso a interro#ao "acilita a visuali>ao e uso o campo. /m vrias situa&es6 o Rails J capa> le#Ivel campo. + resulta o a#ora JA e etectar automaticamente o valor booleano6 e o ponto i>er o tipo e e

interro#ao no J estritamente necessrio. (as J uma boa conveno "a>er isso. Bo s< o c< i#o "ica mais e ime iato6 como qualquer esenvolve or Rails ser capa> e a os arma>ena o no

14

+bviamente6 precisamos e itar o "ato o pro=eto estar ativo ou no. )amos alterar nossa vieG e e ioA

K,1.KY if @pro-e t.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. =ro-e tK/,1. KY! errorAme""age"Afor Qpro-e tQ Y. KY! "tartAformAtag :a tion !. QeditQJ :id !. @pro-e t Y. Kp. Klabel for!Qpro-e tAnameQ.8ame:K/label.Kbr. KY! textAfield Qpro-e tQJ QnameQ Y. K/p. Kp. Klabel for!Qpro-e tAde" riptionQ.Ge" ription:K/label.Kbr. KY! textAarea Qpro-e tQJ Qde" riptionQJ :row" !. 5 Y. K/p. Kp. Klabel for!Qpro-e tAa tiveQ.L tive:K/label.Kbr. KY! "ele t Qpro-e tQJ Qa tiveQJ ))QFe"QJ true+J )Q8oQJ fal"e++ Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p. KY! endAformAtag Y.

/ssa J uma as maneiras e e itar o atributo6 usan o um elemento select. + mJto o select #era automaticamente o c< i#o 4:(L necessrio6 receben o parLmetros similares aos outros mJto os e uma lista um arra, e valores a serem usa os como escolhas. /sses valores so in"orma os como escrio e o valor a ser atribuI o. Bo e arra,s on e ca a item representa um par6 conten o a

caso acima6 temos escri&es Ces e Bo6 correspon en o a valores true e "alse.
15

+ Rails

e"ine uma sJrie

e outros mJto os capa>

e #erar elementos select. Al#uns

esses mJto os so iversos "ormatos e

especiali>a os em #erar cole&es aninha as6 por e0emplo6 enquanto outros #eram ata. Antes e e0perimentar o mJto o #enJrico acima6 consulte a mJto o que lhe aten a.

ocumentao para ver se e0iste al#um

Lembre;se que6 para valores booleanos6 para que a atribuio "uncione automaticamente6 os valores true e

"alse evem ser necessariamente usa os. Caso contrrio6 a converso automtica e tipos o Rub, entra em
ao e os a os no so processa os apropriamente. + resulta o po e ser visto abai0o e testan o voc@ ver que ele "unciona per"eitamente6 alteran o os valores e acor o com sua escolha sem necessi a e e qualquer co i"icao a icionalA

/0istem pelo menos uas outras iretas maneiras e "a>er a e io e um valor booleano. .ma seria usan o

ra io buttons e chec8bo0es. :estar essas maneiras "ica como um e0ercIcio para o leitor6 lembran o que o
princIpio J o mesmo. .ma Pltima coisa seria mo i"icar o controller para #erar pa#inao automtica. ?sso J "acilmente conse#ui o com uas atuali>a&es.

11

.ma no controllerA

la"" =ro-e t"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @pro-e tApage"J @pro-e t" ! paginate :pro-e t"J :perApage !. 5J :order !. QnameQ end def edit if param"):id+ @pro-e t ! =ro-e t.find%param"):id+( el"e @pro-e t ! =ro-e t.new end if re@ue"t.po"tU @pro-e t.attribute" ! param"):pro-e t+ if @pro-e t."ave fla",):noti e+ ! Q<,e pro-e t wa" "u redire tAto :a tion !. Qli"tQ end end end def delete =ro-e t.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e pro-e t wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully "avedQ

e""fully deletedQ

/ outra na vieGA

K,1.=ro-e t"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew =ro-e tQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.L tiveK/t,. Kt,.L tion"K/t,. K/tr. KY @pro-e t".ea , do Mpro-e tM Y. Ktr. Ktd.KY! pro-e t.name Y.K/td. Ktd.KY! ye"AorAnoU%pro-e t.a tiveU( Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. pro-e t Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. pro-e t TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@pro-e tApage"( Y.K/p.

1!

A mo i"icao no controller usa um mJto o que = mencionamos anteriormente6 paginate6 para encapsular o processo e pa#inar os re#istros e #erar uma lista#em in"ormao retorna a pelo mJto o e pa#inao. +s mJto os usa os so ra>oavelmente simples6 mas6 in"eli>mente6 esto entre Rails e ois os mais ine"icientes e o e p#inas Saqui separa as em cinco re#istros por e p#inas com base na p#inaT. A mo i"icao na vieG6 por sua ve>6 simplesmente cria uma lista

evem ser usa os com cui a o. Bo momento6 entretan o6 com a quanti a e

a os que temos6

eles no che#am a representar um problema. + resulta o epois po e ser visto abai0o. )isuali>an o a primeira p#ina6 temosA

/ em se#ui a6 a se#un a p#ina Snote o parLmetro a icional a .RLTA

15

:erminamos um controller completoHsimples6 mas "uncionalHe6 inclusive6 alteramos o mo elo e a os por trs o mesmo e acor o com nossa necessi a e. A#ora = temos uma base para investi#armos o pr<0imo passo classes e a os. e uma aplicaoA relacionamentos entre

RELACIONAMENTOS
Antes e comearmos a ver os relacionamentos6 vamos unir o nosso pro=eto sob um la,out que pelo menos nos permita nave#ar mais "acilmente. Bosso novo arquivo app/!iews/layouts/application.rb/"icaria assimA

K,tml. K,ead. Ktitle.X<GK/title. KY! "tyle",eetAlin#Atag QdefaultQ Y. KY! "tyle",eetAlin#Atag Q" affoldQ Y. K/,ead. Kbody. K,1 id!Q,eaderQ.X<GK/,1. Kul id!QmenuQ. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 4ontext"QJ : ontroller !. Q ontext"Q Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 =ro-e t"QJ : ontroller !. Qpro-e t"Q Y.K/li. K/ul. Kdiv id!Q ontent"Q.KY! yield Y.K/div. K/body.

12

K/,tml.

/ a st,lesheet que estamos usan o6 default.css4/ essa maneiraA

body S font-family: ZerdanaJ LrialJ "an"-"erif5 font-"ize: 1''Y5 margin: '5 padding: '5 T ,1?,eader S ba #ground- olor: ? 5 olor: w,ite5 padding: 1'px 1'px 15px5 margin: '5 T ul?menu S padding: 5px 1'px5 margin: '5 border-bottom: 1px "olid ? T ul?menu li S di"play: inline5 margin-rig,t: 5px5 font-weig,t: bold5 T ul?menu a S text-de oration: none5 font-weig,t: normal5 T div? ontent" S margin: 1'px5 T div? ontent" ,1 S font-"ize: 13'Y5 font-"tyle: itali 5 T

+ resulta o "inal seriaA

!$

Bo J per"eito por causa

e al#uns

e"eitos no c< i#o 4:(L Scomo o uso e que eu no enten o na a e

ois elementos 41 na p#ina6

tabelas com estilos aplica os primeiro sca""ol

iretamente6 etcT e pelo uso

a st,lesheet scaffold.css6 mas = J uma

melhoria S esconsi eran o6 J claro6 o "ato

esi#n #r"icoT. (o i"ica&es o


emonstrar

#era o para conte0tos "icam como um e0ercIcio para o leitor. + ob=etivo J

como po emos atuali>ar a aplicao sem me0er em qualquer #era as uma ve> que elas tenham si o bem plane=a as.

os controllers e vieGs posteriormente

Para e0empli"icarmos os relacionamentos6 vamos comear com o ca astro

e a&es. .ma ao pertence a

um pro=eto e J e0ecuta o em um etermina o conte0to. ?sso J su"iciente para comearmos o nosso ca astro. Atuali>amos primeiro o arquivo application.rhtml para incluir a nossa nova rea6 temosA

K,tml. K,ead. Ktitle.X<GK/title. KY! "tyle",eetAlin#Atag QdefaultQ Y. KY! "tyle",eetAlin#Atag Q" affoldQ Y.

!1

K/,ead. Kbody. K,1 id!Q,eaderQ.X<GK/,1. Kul id!QmenuQ. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 4ontext"QJ : ontroller !. Q ontext"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 =ro-e t"QJ : ontroller !. Qpro-e t"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 L tion"QJ : ontroller !. Qa tion"QJ :a tion !. Qli"tQ Y.K/li. K/ul. Kdiv id!Q ontent"Q.KY! yield Y.K/div. K/body. K/,tml.

/m se#un o lu#ar6 #eramos o nosso controller. )amos se#uir o mesmo estilo pro=etosA

o controller usa o para

ronaldo@minerva:~/tmp/gtd$ " ript/generate ontroller a tion" index li"t edit delete exi"t" app/ ontroller"/ exi"t" app/,elper"/ reate app/view"/a tion" exi"t" te"t/fun tional/ reate app/ ontroller"/a tion"A ontroller.rb reate te"t/fun tional/a tion"A ontrollerAte"t.rb reate app/,elper"/a tion"A,elper.rb reate app/view"/a tion"/index.r,tml reate app/view"/a tion"/li"t.r,tml reate app/view"/a tion"/edit.r,tml reate app/view"/a tion"/delete.r,tml

Para "acilitar6 vamos uplicar a "uncionali a e presente no ca astro e pro=etos. + nosso controller e a&es "icaria assim6 inicialmenteA

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :perApage !. 5J :order !. Qde" riptionQ end def edit if param"):id+ @a tion ! L tion.find%param"):id+( el"e @a tion ! L tion.new end if re@ue"t.po"tU @a tion.attribute" ! param"):a tion+ if @a tion."ave fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ

e""fully "avedQ

!*

end end end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

-e#ui o por nossa vieG e lista#em6 que "icaria assimA

K,1.L tion"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew L tionQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.Ge" riptionK/t,. Kt,.GoneK/t,. Kt,.L tion"K/t,. K/tr. KY @a tion".ea , do Ma tionM Y. Ktr. Ktd.KY! a tion.de" ription Y.K/td. Ktd.KY! ye"AorAnoU%a tion.doneU( Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. a tion Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. a tion TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@a tionApage"( Y.K/p.

/m6 por "im6 a nossa vieG e e io6 que seriaA

K,1.KY if @a tion.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. L tionK/,1. KY! errorAme""age"Afor Qa tionQ Y. KY! "tartAformAtag :a tion !. QeditQJ :id !. @a tion Y. Kp. Klabel for!Qa tionAde" riptionQ.Ge" ription:K/label.Kbr. KY! textAarea Qa tionQJ Qde" riptionQJ :row" !. 5 Y. K/p. Kp. Klabel for!Qa tionAdoneQ.Gone:K/label.Kbr. KY! "ele t Qa tionQJ QdoneQJ ))QFe"QJ true+J )Q8oQJ fal"e++ Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p.

!'

KY! endAformAtag Y.

Bo tente usar essa vieG para salvar uma ao ain a. 4 um erro sutil na mesma que a iante. As emais vieGs #era as Sindex.rhtml /e delete.rhtmlT po em ser removi as no sero usa as.

iscutiremos mais a aplicao pois

+bviamente6 a vieG acima no inclui to os os atributos presentes na ao. Para incluirmos esses atributos6 vamos consi erar al#umas coisas. + atributos created0at representa a AlJm isso6 atributos com os ata e criao a ao. Atributos termina os em 0at e 0on /so atas e atas e tempos6 respectivamente. updated0at e update0on sero created0on6

automaticamente reconheci os pelo Rails como representan o nomes created0at4

automaticamente atuali>a os pelo Rails e acor o com a necessi a e. :o os quan o o ob=eto "or cria o e os ois Pltimos sempre que o ob=eto "or salvo. Como o Rails obviamente no tem controle sobre o banco tipo caso e os termina os em 0on Stipos e a os e a os6 o esenvolve or J que eve escolher o

a os certo para os mesmos no banco6 usan o date no caso

os termina os em 0at e datetime no

o (,-DL6 J claroHa apte con"orme a necessi a eT. Apesar

isso6 usar um tipo mais ou menos preciso no causa erros e Rails tentar convers&es sempre que necessrio. Bo nosso caso6 ento6 no precisamos ar qualquer valor ao atributo created0at /para que ele se=a salvo.

Ba ver a e6 como esse J um campo que everia ser salvo uma Pnica ve>6 vamos colocar al#uma in"ormao no mo elo para que o mesmo no possa ser atribuI o em "ormulrios6 mas somente em c< i#o ireto.

la"" L tion K L tive2e ord::/a"e attrAprote ted : reatedAat end

/sse

eclarao impe e que esse atributo se=a atuali>a o automaticamente por qualquer atribuio via o servi or. -omente uma atuali>ao ireta via c< i#o "uncionar e essa isso6 no temos que nos preocupar mais com esse atributo. + reverso

"ormulrios ou mJto os provin os como no precisamos eclarao seria attr0accessible.

+ atributo completed0at/representa a ata em que a ao "oi completa a. :ambJm no precisamos e it;lo em nossa vieG6 = que ele po eria ser atribuI o quan o o usurio marcasse a ao como completa a. 7aremos ento a mesma coisa com esse atributo6 mu an o o nosso mo elo paraA

la"" L tion K L tive2e ord::/a"e

!4

attrAprote ted : reatedAatJ : ompletedAat end

Como o campo J atribuI o automaticamente6 o que precisamos "a>er J achar al#uma "orma esse atributo quan o o atributo done6 que representa o "ato ver a eiro. A soluo J sobrescrever o mJto o =ustamente para esse tipo e situaoA e escrita

e mo i"icar

a ao estar completa6 "or marca o como o atributo done6 al#o que o Rails permite

la"" L tion K L tive2e ord::/a"e attrAprote ted : reatedAatJ : ompletedAat def done!%value( if L tive2e ord::4onne tionLdapter"::4olumn.valueAtoAboolean%value( "elf. ompletedAat ! Gate<ime.now el"e "elf. ompletedAat ! nil end writeAattribute%QdoneQJ value( end end

Aqui6 estamos usan o o momento em que o atributo done J recebi o e e0ecutan o a&es e0tras. Bnote o sinal e i#ual6 in ican o que esse J um mJto o e atribuioK no Rub,6 qualquer mJto o termina o com o sinal po e ser automaticamente usa o como se "osse um atributo. + mJto o veri"ica se valor recebi o "oi ver a eiro usan o um mJto o interno o ActiveRecor . /ssa chama a J necessria porque6 e0ceto por nil e

"alse6 qualquer outro valor J consi era o ver a eiro em Rub,6 incluin o >ero e strin#s va>ias. -e sim6 o
atributo completed0at J atuali>a o com a ata atual. -e no6 o atributo J retorna o a um valor nulo. Depois isso6 o valor recebi o para o atributo done J passa o sem mo i"ica&es para a cama a e banco e a os6 usan o o mJto o write0attribute. (esmo que voc@ no precise mo i"icar campos em epen @ncia um o outro6 a tJcnica acima J util para

#uar ar valores converti os Spor e0emplo6 um valor que J in"orma o em #raus6 mas arma>ena o em ra ianos ou vice;versaT. + par e mJto os write0attributeZread0attribute po e ser usa o em con=uno com mJto os que sobrescrevem os mJto os manipulao e a os. 7inalmente6 temos os atributos context0id e pro%ect0id6 que representam as chaves estran#eiras que criamos no banco6 que usaremos para os nossos primeiros relacionamentos entre classes. e acesso que o Rails #era para permitir maior "le0ibili a e a

BELONGS TO
Bo caso esses ois atributos6 po erIamos i>er que uma ao pertence a um conte0to e que pertence a um pro=eto. Bo Rails6 representarIamos isso a se#uinte "ormaA

!5

la"" L tion K L tive2e ord::/a"e attrAprote ted : reatedAatJ : ompletedAat def done!%value( if L tive2e ord::4onne tionLdapter"::4olumn.valueAtoAboolean%value( "elf. ompletedAat ! Gate<ime.now el"e "elf. ompletedAat ! nil end writeAattribute%QdoneQJ value( end belong"Ato : ontext belong"Ato :pro-e t end

/ssas capa>

uas e

eclara&es so su"icientes para criar uma sJrie

e "acili a es no Rails que inclui atribui&es e o que ele re"erencia. + Rails J a tabela pai ao su"i0o

buscas. )e=a que voc@ no precisou 0id. Caso voc@ tenha usan o al#o assimA

i>er na a sobre relacionamento alJm

e u>ir a chave estran#eira quan o ela "or cria a concatenan o o nome a o outro nome6 voc@ po e tambJm

i>er ao Rails qual seria a chave estran#eira

belong"Ato :"ub-e tJ :foreignA#ey !. Q ategoryAidQ

AlJm

essa possibili a e6 h outras op&es na

e"inio

e um relacionamento que valem a pena ser

e0plora as na ocumentao6 incluin o outras con i&es limItro"es para o mesmo. Para ca a relacionamento cria o6 o Rails isponibili>a mJto os que permitem testar a e0ist@ncia e uma

associao6 e"ini;la6 remov@;la e busc;la. )amos usar o console para testar issoA

ronaldo@minerva:~/tmp/gtd$ " ript/ on"ole Doading development environment. .. a tion ! L tion. reate%:de" ription !. QL te"t a tion.Q( !. ?KL tion:'xbR$5383 @newAre ord!fal"eJ @error"!?KL tive2e ord::1rror":'xbR$&*$6' @ba"e!?KL tion:'xbR$5383 ....J @error"!ST.J @attribute"!SQ ontextAidQ!.nilJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.nilJ QdoneQ!.nilJ QidQ!.*J Qde" riptionQ!.QL te"t a tion.QJ Q reatedAatQ!.<,u >ep &1 15:&R:$3 /2< &''*T.

:emos uma ao = salva.

.. a tion.pro-e tAid !. nil .. a tion. ontextAid !. nil .. a tion.pro-e t !. nil

!1

.. a tion. ontext !. nil

Com o relacionamento6 em a io aos atributos vin os o banco e a os temos a#ora outros ois atributos que representam a relao. Po emos atribui;los normalmenteA

.. a tion. ontextAid ! 1 !. 1 .. a tion. ontext !. ?K4ontext:'xbRRaaeb8 @attribute"!SQnameQ!.Q@;omeQJ QidQ!.Q1QT.

+u usar iretamente a relaoA

.. a tion.pro-e t ! =ro-e t.find%1( !. ?K=ro-e t:'xbRRa&da8 @attribute"!SQnameQ!.Q/uild a ;ou"eQJ QidQ!.Q1QJ Qde" riptionQ!.Q/uild a dream ,ou"e entirely planned by my"elfJ in luding a intere"ting atti wit, a ,uge library.QJ Qa tiveQ!.Q1QT. .. a tion.pro-e tAid !. 1

-e quisermos6 po emos criar tambJm novos valores iretamenteA

.. a tion. ontext ! 4ontext. reate%:name !. Q@=,oneQ( !. ?K4ontext:'xbRR6a1d' @newAre ord!fal"eJ @error"!?KL tive2e ord::1rror":'xbRR65aR @ba"e!?K4ontext:'xbRR6a1d' ....J @error"!ST.J @attribute"!SQnameQ!.Q@=,oneQJ QidQ!.3T.

Relacionamentos so bem Pteis6 mas precisamos ter um pouco e cui a o em como os usamos. Aqui entra a necessi a e e conhecimento e -DL que mencionamos anteriormente. )e=a o caso abai0o6 por e0emploA

.. L tion.find%*(.pro-e t.name !. Q/uild a ;ou"eQ

-e e0ecutarmos a ao acima e e observamos o lo# log/de!elopment.logT6 veremos o se#uinteA

esenvolvimento #era o pelo Rails Sque est em

L tion Doad %'.''&681( =ro-e t Doad %'.''1&5$(

>1D14< P 92:B a tion" 0;121 %a tion".id ! *( D7B7< 1 >1D14< P 92:B pro-e t" 0;121 %pro-e t".id ! 1( D7B7< 1

?sso mostra que

uas chama as "oram "eitas ao banco para carre#ar o nome

o pro=eto

a ao busca a6

uma elas completamente esnecessria. +bviamente6 se "i>ermos isso em um loop6 com mPltiplos ob=etos e relacionamentos6 o nIvel e ine"ici@ncia subir rapi amente.

!!

Para isso6 o Rails tem uma soluo que resolve a maior parte

os problemas causa os por isso6 #eran o

=oins automaticamente e acor o com o que o usurio precisa.


Por e0emploA

.. L tion.find%*J :in lude !. ):pro-e tJ : ontext+( !. ?KL tion:'xbRR*6*f' @ ontext!?K4ontext:'xbRR*8818 @attribute"!SQnameQ!.Q@=,oneQJ QidQ!.Q3QT.J @pro-e t!?K=ro-e t:'xbRR*8a$8 @attribute"!SQnameQ!.Q/uild a ;ou"eQJ QidQ!.Q1QJ Qde" riptionQ!.Q/uild a dream ,ou"e entirely planned by my"elfJ in luding a intere"ting atti wit, a ,uge library.QJ Qa tiveQ!.Q1QT.J @attribute"!SQ ontextAidQ!.Q3QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.Q1QJ QdoneQ!.nilJ QidQ!.Q*QJ Qde" riptionQ!.QL te"t a tion.QJ Q reatedAatQ!.Q&''*-'6-&1 15:&R:$3QT.

Como voc@ po e ver6 tanto o conte0to como o pro=eto "oram automaticamente recupera os. -e observamos o

lo#6 veremos o se#uinteA

L tion Doad 7n luding L""o iation" %'.&3&'R&( >1D14< a tion".\id\ L> t'Ar'J a tion".\de" ription\ L> t'Ar1J a tion".\done\ L> t'Ar&J a tion".\ reatedAat\ L> t'Ar3J a tion".\ ompletedAat\ L> t'Ar$J a tion".\ ontextAid\ L> t'Ar5J a tion".\pro-e tAid\ L> t'Ar*J pro-e t".\id\ L> t1Ar'J pro-e t".\name\ L> t1Ar1J pro-e t".\de" ription\ L> t1Ar&J pro-e t".\a tive\ L> t1Ar3J ontext".\id\ L> t&Ar'J ontext".\name\ L> t&Ar1 92:B a tion" D19< :O<12 ]:78 pro-e t" :8 pro-e t".id ! a tion".pro-e tAid D19< :O<12 ]:78 ontext" :8 ontext".id ! a tion". ontextAid 0;121 %a tion".id ! *(

Ao invJs

uas

eclarao temos somente uma. Para relacionamentos mPltiplos6 isso po e re u>ir

centenas ou milhares e chama as ao banco em uma Pnica chama a. )e=a por e0emplo a i"erena entre as uas chama as abai0o6 epois e criarmos tr@s a&esA

.. L tion.find%:all(. olle t S MaM )a.pro-e t.nameJ a. ontext.name+ T !. ))Q/uild a ;ou"eQJ Q@;omeQ+J )Q=lant a <reeQJ Q@0or#Q+J )Q0rite a /oo#QJ Q@;omeQ++

+ ob=etivo

a chama a J retornar uma coleo

os nomes

os pro=etos e conte0tos

e ca a ao e0iste no

banco6 em pares. A chama a acima #era os se#uintes coman osA

L tion Doad %'.''&R38( =ro-e t Doad %'.''&1*1( 4ontext Doad %'.'''83$( =ro-e t Doad %'.''1&&'( 4ontext Doad %'.''111*( =ro-e t Doad %'.''1&&8( 4ontext Doad %'.''1'RR(

>1D14< P 92:B a tion" >1D14< P 92:B pro-e t" >1D14< P 92:B ontext" >1D14< P 92:B pro-e t" >1D14< P 92:B ontext" >1D14< P 92:B pro-e t" >1D14< P 92:B ontext"

0;121 0;121 0;121 0;121 0;121 0;121

%pro-e t".id % ontext".id %pro-e t".id % ontext".id %pro-e t".id % ontext".id

! ! ! ! ! !

1( 1( &( &( 3( 1(

D7B7< D7B7< D7B7< D7B7< D7B7< D7B7<

1 1 1 1 1 1

A#ora6 vamos mu ar a chama a paraA

.. L tion.find%:allJ :in lude !. ):pro-e tJ : ontext+(. olle t S MaM )a.pro-e t.nameJ a. ontext.name+ T !. ))Q/uild a ;ou"eQJ Q@;omeQ+J )Q=lant a <reeQJ Q@0or#Q+J )Q0rite a /oo#QJ Q@;omeQ++

)eremos6 ao e0ecut;la6 que somente uma chama a ser "eitaA

!5

L tion Doad 7n luding L""o iation" %'.''$515( >1D14< a tion".\id\ L> t'Ar'J a tion".\de" ription\ L> t'Ar1J a tion".\done\ L> t'Ar&J a tion".\ reatedAat\ L> t'Ar3J a tion".\ ompletedAat\ L> t'Ar$J a tion".\ ontextAid\ L> t'Ar5J a tion".\pro-e tAid\ L> t'Ar*J pro-e t".\id\ L> t1Ar'J pro-e t".\name\ L> t1Ar1J pro-e t".\de" ription\ L> t1Ar&J pro-e t".\a tive\ L> t1Ar3J ontext".\id\ L> t&Ar'J ontext".\name\ L> t&Ar1 92:B a tion" D19< :O<12 ]:78 pro-e t" :8 pro-e t".id ! a tion".pro-e tAid D19< :O<12 ]:78 ontext" :8 ontext".id ! a tion". ontextAid

V "cil ver que essa chama a J bem melhor o que as emais e isso consi eran o al#uns poucos re#istros. /m casos e mo elos mais comple0os6 a partir o Rails 1.1 a eclarao inclu e J recursiva. )oc@ po eria

ter al#o como A

@order" ! :rdem.find :allJ :in lude !. ):item" !. S :produ tJ :di" ount TJ :"ale"per"on+

+ c< i#o acima buscaria to as as or ens ob=etos escreven o o pro uto associa o e o

e compra presentes em um banco esconto

a os6 carre#an o

automaticamente seus itens e a pessoa que a ven eu. AlJm

isso6 para os itens6 tambJm carre#aria os

a o. As combina&es so in"initas e basta voc@

manter a possibili a e em mente para aplic;la em suas pr<prias aplica&es. )amos a#ora intro u>ir nossa mo i"icao "inal em nosso mo elo e a os6 as vali a&esA

la"" L tion K L tive2e ord::/a"e attrAprote ted : reatedAatJ : ompletedAat def done!%value( if L tive2e ord::4onne tionLdapter"::4olumn.valueAtoAboolean%value( "elf. ompletedAat ! Gate<ime.now el"e "elf. ompletedAat ! nil end writeAattribute%QdoneQJ value( end belong"Ato : ontext belong"Ato :pro-e t validate"Apre"en eAof :de" ription validate"Apre"en eAof : ontextAid validate"Apre"en eAof :pro-e tAid end

A#ora que temos os nossos relacionamentos6 po emos atuali>ar o nosso controller e as vieGs #era as para o mesmo. Primeiro6 o controllerA

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end

!2

def li"t @a tionApage"J @a tion" ! paginate :a tion"J :perApage !. 5J :order !. Qde" riptionQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if param"):id+ @a tion ! L tion.find%param"):id+( el"e @a tion ! L tion.new end if re@ue"t.po"tU @a tion.attribute" ! param"):a tion+ if @a tion."ave fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

As

uas linhas acrescenta as criam arra,s

e pares com os nomes e i enti"ica ores

os ob=etos busca os.

Precisamos esses arra,s para a nossa vieG e e io6 como vemos abai0oA

K,1.KY if @a tion.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. L tionK/,1. KY! errorAme""age"Afor Qa tionQ Y. KY! "tartAformAtag :a tion !. QeditQJ :id !. @a tion Y. Kp. Klabel for!Qa tionAde" riptionQ.Ge" ription:K/label.Kbr. KY! textAarea Qa tionQJ Qde" riptionQJ :row" !. 5 Y. K/p. Kp. Klabel for!Qa tionAdoneQ.Gone:K/label.Kbr. KY! "ele t Qa tionQJ QdoneQJ ))QFe"QJ true+J )Q8oQJ fal"e++ Y. K/p. Kp. Klabel for!Qa tionA ontextAidQ.4ontext:K/label.Kbr. KY! "ele t Qa tionQJ Q ontextAidQJ @ ontext"J :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. Klabel for!Qa tionApro-e tAidQ.=ro-e t:K/label.Kbr. KY! "ele t Qa tionQJ Qpro-e tAidQJ @pro-e t"J :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p. KY! endAformAtag Y.

5$

-elecionar os ob=etos e #erar as estruturas que precisamos no controller J um prtica recomen a a porque mantemos a nossa vieG limpa e po emos "a>er quaisquer or ena&es e "iltros sem nos preocuparmos com o

esi#n

a aplicao. + parLmetro prompt6 passa o acima6 permite que um in ica or

a seleo aparea

antes os valores propriamente itos. + "ormulrio resultante "ica assimA

A#ora voltamos ao pequeno problema que in icamos e0istir nesse controller anteriormente. -e voc@ tentar salvar uma ao a#ora6 ver que um erro aconteceA

51

/sse erro J causa o por um etalhe. Bo Rails6 a chave params5:action6 = J toma a pelo nome a ao que est sen o e0ecuta a e como temos um ob=eto com esse nome6 acabamos com um problema. /ntretanto6 a soluo J simplesA basta renomear o nosso ob=eto. Po emos6 por e0emplo6 cham;lo e item. Primeiro6 mu amos o controllerA

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :perApage !. 5J :order !. Qde" riptionQ end def edit

5*

@ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end if re@ue"t.po"tU @item.attribute" ! param"):item+ if @item."ave fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

/ epois mu amos a vieGA

K,1.KY if @item.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. L tionK/,1. KY! errorAme""age"Afor QitemQ Y. KY! "tartAformAtag :a tion !. QeditQJ :id !. @item Y. Kp. Klabel for!QitemAde" riptionQ.Ge" ription:K/label.Kbr. KY! textAarea QitemQJ Qde" riptionQJ :row" !. 5 Y. K/p. Kp. Klabel for!QitemAdoneQ.Gone:K/label.Kbr. KY! "ele t QitemQJ QdoneQJ ))Q8oQJ fal"e+J )QFe"QJ true++ Y. K/p. Kp. Klabel for!QitemA ontextAidQ.4ontext:K/label.Kbr. KY! "ele t QitemQJ Q ontextAidQJ @ ontext"J :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. Klabel for!QitemApro-e tAidQ.=ro-e t:K/label.Kbr. KY! "ele t QitemQJ Qpro-e tAidQJ @pro-e t"J :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p. KY! endAformAtag Y.

/sse J um caso raro6 mas se voc@ vir al#um erro misterioso acontecen o "uncionan o6 veri"ique se no h um con"lito. Como um etalhe e0tra6 invertemos acima a or em

o Rails on e tu o

everia estar

o Ces e Bo na seleo a situao ativa para o correto

que seriam uma ao ain a no concluI a por pa ro. Ro an o a#ora a ao6 temos o resulta o ese=a o.
5'

)amos a#ora mo i"icar o controller mais uma ve> em apoio M vieG se#uinteA

e lista#em

os

a os. :erIamos o

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end if re@ue"t.po"tU @item.attribute" ! param"):item+ if @item."ave fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

A incluso os relacionamentos ir melhorar a nossa vieG. )e=a que precisamos a#ora especi"icar a con io e or enao mais claramente6 = que temos uma coluna chama a description em uas tabelas. Bossa vieG "icaria assimA

K,1.L tion"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew L tionQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q Ktr. Kt,.Ge" riptionK/t,. Kt,.4ompletedK/t,. Kt,.=ro-e tK/t,. Kt,.4ontextK/t,. Kt,.L tion"K/t,. K/tr. KY @a tion".ea , do Ma tionM Y. ell"pa ing!Q1Q.

54

Ktr. Ktd.KY! a tion.de" ription Y.K/td. Ktd.KY! ye"AorAnoU%a tion.doneU( Y.K/td. Ktd.KY! a tion.pro-e t.name Y.K/td. Ktd.KY! a tion. ontext.name Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. a tion Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. a tion TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@a tionApage"( Y.K/p.

Dan o o se#uinte resulta oA

-e quisermos6 po emos tambJm acrescentar um campo in"orman o quan o a ao "oi completa a6 "ormatan o a ata em que a mesma "oi completa a a maneira necessria M nossa aplicao6 ou e0ibin o um marca or caso contrrio. Bossa vieG po eria "icar como al#o assimA

K,1.L tion"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew L tionQJ :a tion !. QeditQ Y.K/p.

55

Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.Ge" riptionK/t,. Kt,.4ompletedK/t,. Kt,.0,enK/t,. Kt,.=ro-e tK/t,. Kt,.4ontextK/t,. Kt,.L tion"K/t,. K/tr. KY @a tion".ea , do Ma tionM Y. Ktr. Ktd.KY! a tion.de" ription Y.K/td. Ktd.KY! ye"AorAnoU%a tion.doneU( Y.K/td. Ktd.KY! %a tion.doneU( U a tion. ompletedAat."trftime%QYm/Yd/YyQ( : Q-Q Y.K/td. Ktd.KY! a tion.pro-e t.name Y.K/td. Ktd.KY! a tion. ontext.name Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. a tion Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. a tion TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@a tionApage"( Y.K/p.

Com o se#uinte resulta oA

51

HAS MANY
AlJm o relacionamento belongs0to4 o Rails tambJm possui um outro relacionamento chama o has0many. i> que um mo elo possui muitos e outros mo elos. /m issoA um conte0to possui muitas a&es e um pro=eto uas instLncias ime iatas Como o pr<prio nome in ica6 esse relacionamento nossa aplicao6 nos temos possui muitas a&es. (o i"ican o inicialmente o mo elo e conte0tos6 terIamosA

la"" 4ontext K L tive2e ord::/a"e validate"Apre"en eAof :name validate"Auni@uene""Aof :nameJ :me""age !. Qmu"t be uni@ueQ ,a"Amany :a tion" end

?sso J su"iciente para estabelecer uma sJrie

e mJto os a icionais que permitem que voc@ manipule as

a&es relaciona as a um conte0to. .san o o console6 po emos ver al#umas elasA

ronaldo@minerva:~/tmp/gtd$ " ript/ on"ole Doading development environment. .. ontext ! 4ontext.find%1( !. ?K4ontext:'xbR3ff1f8 @attribute"!SQnameQ!.Q@;omeQJ QidQ!.Q1QT. .. ontext.a tion". ount !. 1 .. ontext.a tion" !. )?KL tion:'xbR3f&6* @attribute"!SQ ontextAidQ!.Q1QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.Q3QJ QdoneQ!.Q'QJ QidQ!.Q6QJ Qde" riptionQ!.Q>it down and writeJ every dayJ at lea"t two ,our" a day.QJ Q reatedAatQ!.Q&''*-'6-&1 1*:31:1$QT.+

-e criarmos mais uma ao associa a a esse conte0to6 terIamos al#o assimA

.. a tion ! L tion. reate%:de" ription !. Q/uy a grammar to ,elp me wit, my 1ngli",.QJ : ontextAid !. 1J :pro-e tAid !. 3( !. ?KL tion:'xbR8f5$$8 @newAre ord!fal"eJ @error"!?KL tive2e ord::1rror":'xbR8e8*$$ @ba"e!?KL tion:'xbR8f5$$8 ....J @error"!ST.J @attribute"!SQ ontextAidQ!.1J Q ompletedAatQ!.nilJ Qpro-e tAidQ!.3J QdoneQ!.nilJ QidQ!.11J Qde" riptionQ!.Q/uy a grammar to ,elp me wit, my 1ngli",.QJ Q reatedAatQ!.<,u >ep &1 1*:5&:$' /2< &''*T. .. ontext.a tion" !. )?KL tion:'xbR3f&6* @attribute"!SQ ontextAidQ!.Q1QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.Q3QJ QdoneQ!.Q'QJ QidQ!.Q6QJ Qde" riptionQ!.Q>it down and writeJ every dayJ at lea"t two ,our" a day.QJ Q reatedAatQ!.Q&''*-'6-&1 1*:31:1$QT.+ .. ontext.a tion".reload !. )?KL tion:'xbRRR8* @attribute"!SQ ontextAidQ!.Q1QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.Q3QJ QdoneQ!.Q'QJ QidQ!.Q6QJ Qde" riptionQ!.Q>it down and writeJ every dayJ at lea"t two ,our" a day.QJ Q reatedAatQ!.Q&''*-'6-&1 1*:31:1$QT.J ?KL tion:'xbRRR8*6' @attribute"!SQ ontextAidQ!.Q1QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.Q3QJ QdoneQ!.nilJ QidQ!.Q11QJ Qde" riptionQ!.Q/uy a grammar to ,elp me wit, my 1ngli",.QJ Q reatedAatQ!.Q&''*-'6-&1 1*:5&:$'QT.+

5!

.. ontext.a tion". ount !. & .. ontext.a tion".emptyU !. fal"e

Bote que6 como usan o um ob=eto = carre#a o6 a coleo atravJs e seu pr<prio constructor e no usan o os mJto os

e a&es no "oi recarre#a a

epois que uma

nova ao "oi a iciona a. ?sso acontece porque o Rails "a> um cache para recarre#ar a coleo caso voc@ precise. .m outro e0emplo seriaA

e cole&es e a ao "oi a iciona a

a coleo. + mJto o reload po e ser usa o

.. ontext.a tion" KK L tion. reate%:de" ription !. QOpgrade my word pro e""or.QJ :pro-e tAid !. 3( !. )?KL tion:'xbRRR8* @attribute"!SQ ontextAidQ!.Q1QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.Q3QJ QdoneQ!.Q'QJ QidQ!.Q6QJ Qde" riptionQ!.Q>it down and writeJ every dayJ at lea"t two ,our" a day.QJ Q reatedAatQ!.Q&''*-'6-&1 1*:31:1$QT.J ?KL tion:'xbRRR8*6' @attribute"!SQ ontextAidQ!.Q1QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.Q3QJ QdoneQ!.nilJ QidQ!.Q11QJ Qde" riptionQ!.Q/uy a grammar to ,elp me wit, my 1ngli",.QJ Q reatedAatQ!.Q&''*-'6-&1 1*:5&:$'QT.J ?KL tion:'xbRR531*' @newAre ord!fal"eJ @error"!?KL tive2e ord::1rror":'xbRR513b' @ba"e!?KL tion:'xbRR531*' ....J @error"!ST.J @attribute"!SQ ontextAidQ!.1J Q ompletedAatQ!.nilJ Qpro-e tAidQ!.3J QdoneQ!.nilJ QidQ!.1&J Qde" riptionQ!.QOpgrade my word pro e""or.QJ Q reatedAatQ!.<,u >ep &1 1*:56:&1 /2< &''*T.+ .. ontext.a tion"."ize !. 3

Besse caso6 voc@ po e ver que

uas coisas aconteceramA primeiro6 no "oi necessrio in"ormar o conte0to6

que J pe#o automaticamente no ob=etoK se#un oA a coleo cresceu automaticamente6 = que estamos manipulan o os a os iretamente na mesma. Ao invJs e usar os mJto os acima para criar a ao6 voc@ po e usar iretamente os mJto os build e

create na coleo para a icionar novos a os. + primeiro "unciona para ob=etos = e0istentes na coleo e o se#un o para a icionar um novo ob=eto. .ma coleo tambJm possui um mJto o find para encontrar ob=etos mesmas re#ras o mJto o find usa o para classes e a os. Por "im6 por ra>&es valores. Bo caso e e"ici@ncia6 to a coleo eclara um mJto o o ob=eto pai para atribuio rpi a e entro a mesma6 e acor o com as

o ob=eto acima6 o mJto o J chama a action0ids e po e ser usa o para trocar

completamente os a os e uma coleo. Por e0emploA

ontext.a tionAid" ! )1J &J *+

?sso removeria qualquer ao associa a Mquele conte0to6 substituin o;as pelas a&es i enti"ica as pelos i s acima.

55

A coleo to a po e ser substituI a com ob=etos tambJm6 como mostra o abai0oA

ontext.a tion" ! L tion.find%:allJ : ondition" !. )Qpro-e tAid ! UQJ 5+(

+ conte0to acima teria to as as suas a&es substituI as pelas a&es associa as ao pro=eto cu=o i J 5. ?nvesti#an o a e0emplo ocumentao voc@ po er encontrar mais estruio automtica etalhes sobre como ca a mJto o "unciona. .m

isso J a

e re#istros quan o um re#istro pai "or e0cluI o. ?sso po e "a>er

um ob=eto ter a "uncionali a e equivalente e uma eclarao casca e em um banco e a os. .ma coisa que eve ser nota a J que muitos esse mJto os causam o salvamento ime iato os ob=eto pai = est salvoT. Com a prtica6 voc@ ser capa> os casos. Bo vamos utili>ar esses mJto os em nossa aplicao no momento porque veremos uma aplicao similar mais M "rente com outro tipo e relacionamento pareci o. apropria amente caso queria outra ao6 embora o comportamento pa ro se=a o a os Sse o

e i enti"icar quais so esses mJto os e a#ir ese=a o na maior parte

HAS ONE
Dois outros relacionamentos e0istentes no Rails so has0and0belongs0to0many e has0one. + relacionamento has0one #eralmente e0pressa o oposto i#amos que temos as se#uintes classesA uas tabelasA uma conten o cart&es o relacionamento belongs0to. Por e0emplo6 e cart&es.

e crJ ito e outra conten o o titulares

Ba tabela e carto e crJ ito terIamos uma chave estran#eira apontan o para o seu titular. :erIamos ento

la"" 4redit4ard K L tive2e ord::/a"e belong"Ato :a ountA,older end la"" L ount;older K L tive2e ord::/a"e ,a"Aone : reditA ard end

i"erena J que a chave estran#eira e0iste somente na tabela relaciona a M classe 7redit7ard6 sen o

automaticamente e u>i a no relacionamento inverso. /sse e0emplo no J muito bom = que6 em tese6 uma pessoa po eria ter vrios cart&es i Jia J essa. Ba prtica6 esse tipo relacionamentos o tipo has0many/ou has0many0and0belongs0to. + relacionamento has0many0and0belongs0to6 por sua ve>6 representa a interme iao entre uas tabelas. e crJ ito. (as a

e relacionamento J mais raro e #eralmente ten e a se trans"ormar em

52

Por e0emplo6 a relao entre

esenvolve ores e pro=etos em uma empresa. .m

esenvolve or po e estar

loca o em mPltiplos pro=etos e um pro=eto po e ter mPltiplos esenvolve ores. )eremos mais etalhes esse relacionamento a iante quan o "i>ermos mais mo i"ica&es em nossa aplicao para suportar outras caracterIsticas.

HAS MANY, THROUGH


.m tipo interessante e relacionamento6 intro u>i o no Rails 1.16 J aquele relacionamento em que uma escobrir to as as notas "iscais emiti as por tabela interme iria J usa a para colapsar outra. Di#amos6 por e0emplo6 que voc@ tenha mo elos representan o empresas6 clientes e notas "icais e voc@ queira um empresa qualquer. V aqui que esse tipo simpli"ica o. )amos e0perimentar um pouco6 usan o o console. Di#amos que voc@ queria6 em nossa aplicao6 saber to os os conte0tos associa os a um pro=eto. A maneira simples seria "a>er issoA e relacionamento entra em ao6 permitin o que o c< i#o se=a

ronaldo@minerva:~/tmp/gtd$ " ript/ on"ole Doading development environment. .. pro-e t ! =ro-e t.find%3( !. ?K=ro-e t:'xbR8'83f @attribute"!SQnameQ!.Q0rite a /oo#QJ QidQ!.Q3QJ Qde" riptionQ!.QQJ Qa tiveQ!.Q1QT. .. pro-e t.a tion". olle t S MaM a. ontext.name T !. )Q@;omeQJ Q@;omeQJ Q@;omeQ+

Como voc@ po e ver6 o conte0to J o mesmo para to as as a&es associa as Mquele pro=eto e queremos os conte0tos sem repetio. .ma soluo simples seriaA

.. ontext" ! pro-e t.a tion". olle t S MaM a. ontext.name T !. )Q@;omeQJ Q@;omeQJ Q@;omeQ+ .. ontext".uni@ !. )Q@;omeQ+

+ problema J que6 alJm estratJ#iaA

e usar mais c< i#o6 essa soluo J muito ine"iciente por causa

as compara&es

que precisam ser reali>a as pelo mJto o uniq. Po emos resolver o problema usan o ento a se#uinte

la"" =ro-e t K L tive2e ord::/a"e validate"Apre"en eAof :name validate"Auni@uene""Aof :name ,a"Amany :a tion" ,a"Amany : ontext"J :t,roug, !. :a tion"J :"ele t !. Qdi"tin t end ontext".PQ

2$

.san o esse mJto o temposA

.. pro-e t. ontext". olle t S M M !. )Q@;omeQ+

.name T

Como voc@ po e ver6 muito mais "cil e interessante e6 em quase to os os casos6 mais e"iciente. Bo relacionamento acima6 temos os conte0tos e um pro=ecto obti os atravJs Sthrou#hT e suas a&es. -e

no "or necessrio preocupar com c<pias Scomo no e0emplo as notas "iscaisT po eremos inclusive escartar o parLmetro select que J um "ra#mento e -DL usa o no lu#ar o #era o automaticamente pelo Rails. Associa&es throu#h so muito po erosas e po em ser utili>a as em vrias situa&es para a#ili>ar o c< i#o e melhorar a le#ibili a e a aplicao (ais a iante6 veremos tambJm outra e0tenso e associa&es has0many conheci as como associa&es

polim<r"icas6 que tambJm po e ser usa as para mais combina&es interessantes e mo elos e a os. A#ora que = vimos o bsico para um aplicao6 J hora e "ocar em al#uns t<picos mais avana os.

Avanando no Rails
FILTROS
Bossa aplicao atJ o momento estaria permiti os. )amos6 ento6 a icionar um sistema rpi o al#uns conceitos e autenticao M aplicao6 aproveitan o para e0plorar mais e isponIvel para qualquer pessoa que ese=asse us;la. /m um e usurios cenrio normal6 provavelmente #ostarIamos e restrin#ir acesso para somente um #rupo

o Rails. .ma observao aqui J que e0istem plu#ins prontos com sistemas

autenticao "uncionais6 plenamente customi>veis. Como tu o no Rails6 a escolha J sua. A primeira coisa que temos que "a>er J criar uma tabela representar a nossa tabelaA e usurios para conter os lo#ins e senhas as

pessoas que po ero acessar o sistema. Para isso6 vamos se#uir o caminho "amiliar6 #eran o um mo el para

ronaldo@minerva:~/tmp/gtd$ " ript/generate model u"er exi"t" app/model"/ exi"t" te"t/unit/ exi"t" te"t/fixture"/ reate app/model"/u"er.rb reate te"t/unit/u"erAte"t.rb reate te"t/fixture"/u"er".yml

21

exi"t" reate

db/migrate db/migrate/''5A reateAu"er".rb

/ itan o a mi#rao #era a6 "icarIamos6 pensan o em al#o bem bsico6 com o se#uinteA

la"" 4reateO"er" K L tive2e ord::Bigration def "elf.up reateAtable :u"er" do MtM t. olumn :nameJ :"tring t. olumn :loginJ :"tringJ :limit !. 1' t. olumn :pa""wordJ :"tringJ :limit !. 1' end O"er.re"etA olumnAinformation O"er. reate%:name !. Q2onaldoQJ :login !. QronaldoQJ :pa""word !. Qte"tQ( end def "elf.down dropAtable :u"er" end end

Bote o uso precisarmos

o parLmetro limit para #erar campos te0to com um tamanho menor e que = estou crian o um epois e termos mo i"ica o a aplicao sem e criar um ca astro e usurios ime iatamente. /sse ca astro "ica como um e0ercIcio para o

usurio inicial para po ermos e"etuar autenticao lo#o

leitor6 sen o uma boa oportuni a e para usar vali a&es como !alidates0confirmation0of4 que voc@ po e achar na ocumentao o Rails. + que precisamos a#ora J al#uma maneira e0ecuta os antes ou e0ecuta os antes epois e bloquear o acesso aos nossos controllers = cria os caso o e "iltros6 que so mJto os e "iltrosA os epois e uma e uma ao. + Rails possui tr@s tipos e uma ao e os e0ecuta os antes e

usurio no este=a autentica o. ?sso J conse#ui o com al#o que o Rails chama o processamento e uma ao6 os e0ecuta os epois

ao Saroun "ilters6 na terminolo#ia a ocumentaoT. Dualquer "iltro em Rails po e retornar um valor "also para bloquear o processamento posterior a ao. Bo nosso caso6 J e0atamente isso que precisamosA caso um usurio no este=a autentica o6 no permitiremos que ele acesse um controller. Como queremos "a>er isso para to os os nossos controllers e0istentes6 usaremos um "iltro no controller qual to os os outros so se o usurio est ou no autentica o6 usaremos uma varivel e sesso. (o i"ican o o nosso c< i#o6 inicialmente terIamos al#o assimA o

eriva osA o -pplication7ontroller6 = menciona o anteriormente. / para saber

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :aut,enti ate prote ted

2*

def aut,enti ate unle"" "e""ion):u"er+ fal"e end end end

Bo c< i#o acima6 a menos que tenhamos uma varIavel "also6 bloquean o o processamento

e sesso chama a session5:user66 retornaremos

a ao. -e voc@ ro ar qualquer controller a#ora6 ver que uma tela

completamente va>ia ser retorna a6 sem nem mesmo o c< i#o o la,out. +bviamente6 o que precisamos J e uma "orma e permitir que o usurio "aa sua autenticao. )amos

mo i"icar o c< i#o acima para li ar com com essa possibili a e e enviar o usurio para um local on e ele possa "a>er autenticao caso ain a no tenha "eitoA

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :aut,enti ate prote ted def aut,enti ate unle"" "e""ion):u"er+ "e""ion):returnAto+ ! re@ue"t.re@ue"tAuri redire tAto : ontroller !. QloginQJ :a tion !. QloginQ return fal"e end return true end end

+ nosso c< i#o a#ora veri"ica se e0iste uma varivel

e sesso que precisamos. -e a varivel no e0istir6

re irecionamos o usurio para um novo controller que "ara a sua autenticao. Besse caso6 retornamos "also para bloquear o resto a ao6 se=a qual "or. -e a varivel e0istir6 simplesmente retornamos ver a eiro para ei0ar que o c< i#o si#a seu caminho usual. .m toque a icional J salvar a .RL que o usurio tentou acessar para retornar a ela uma ve> que a autenticao se=a "eita. A#ora6 precisamos e nosso controller e autenticao. / alJm a autenticao6 po emos tambJm permitir epois que ele saiu a aplicao. -en o

que o usurio encerre sua sesso6 para que ela no "ique aberta

assim6 precisamos e uas a&esA lo#in e lo#out. De acor o com isso6 #eramos o controller abai0oA

ronaldo@minerva:~/tmp/gtd$ " ript/generate ontroller login login logout exi"t" app/ ontroller"/ exi"t" app/,elper"/ reate app/view"/login exi"t" te"t/fun tional/ reate app/ ontroller"/loginA ontroller.rb reate te"t/fun tional/loginA ontrollerAte"t.rb reate app/,elper"/loginA,elper.rb reate app/view"/login/login.r,tml reate app/view"/login/logout.r,tml

2'

-e voc@ ro ar uma p#ina qualquer a#ora ver que o servi or entra um loop in"inito. ?sso acontece por causa e um etalhe "un amentalA o controller que acabamos e criar tambJm est su=eito ao "iltro. A soluo J simples. 3asta a icionar uma linha ao controllerA

la"" Dogin4ontroller K Lppli ation4ontroller "#ipAbeforeAfilter :aut,enti ateJ :only !. ):login+ def login end def logout end end

A linha acima instrui o controller a i#norar o "iltro boa prtica na a ao.

e autenticaao6 somente para a ao lo#in. /ssa J um

e se#urana6 "a>en o e0clus&es somente quan o necessrio. Bo caso acima6 mesmo para a

ao lo#out terIamos que estar autentica os. Ba nossa implementao J provvel que essa ao no "aa e mais. /m um implementao real6 porJm6 ela po eria ser to importante quanto qualquer outra

Resolvi o esse problema6 po emos partir para a nossa implementao se=a capa> e "a>er sua autenticao6 precisamos responsvel pela autenticao6 app/!iews/login/login.rhtmlA

a autenticao. Para que o usurio

e um "ormulrio. Para isso vamos alterar a vieG

K,1.Dogin to >iteK/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: red5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. KY! "tartAformAtag :a tion !. QloginQ Y. Kp.=lea"eJ enter your login and pa""word to aut,enti ate to t,i" "ite:K/p. Kp. Klabel for!QloginQ.Dogin:K/label.Kbr. KY! textAfieldAtag QloginQJ param"):login+J :maxlengt, !. 1' Y. K/p. Kp. Klabel for!Qpa""wordQ.=a""word:K/label.Kbr. KY! pa""wordAfieldAtag Qpa""wordQJ QQJ :maxlengt, !. 1' Y. K/p. Kp. KY! "ubmitAtag Q1nterQ Y. K/p. KY! endAformAtag Y.

)e=a que estamos usan o verso acontece porque no precisamos

i"erentes e atribuir

os mJto os a os
24

e #erao

e campos

e "ormulrios. ?sso a os e os mesmos J

a os a um ob=eto6 mas simplesmente recolher os e um ob=eto6 o se#un o parLmetro

autenticao. Como esses mJto os no recebem

um valor a ser iniciali>a o. Bo caso6 usamos um lo#in previamente submeti o para preencher o campo

lo#in caso ele e0ista6 e sempre


preparamos tambJm um "orma

ei0amos a senha em branco e avisar ao usurio em casos

epois e "alhas

e uma "alha

e autenticao. Q

e autenticao6 usan o variveis

"lash.
:erIamos o se#uinte resulta oA

Precisamos a#ora mo i"icar o nosso controller para reali>ar a autenticaoA

la"" Dogin4ontroller K Lppli ation4ontroller "#ipAbeforeAfilter :aut,enti ateJ :only !. ):login+ def login if re@ue"t.po"tU @u"er ! O"er.findAbyAloginAandApa""word%param"):login+J param"):pa""word+( if @u"er "e""ion):u"er+ ! @u"er.id if "e""ion):returnAto+ [[ W"e""ion):returnAto+.in ludeU%urlAfor%:a tion !. QloginQ(( redire tAto "e""ion):returnAto+ "e""ion):returnAto+ ! nil el"e redire tAto : ontroller !. Q,omeQ end el"e fla",):noti e+ ! Q7nvalid login and/or pa""word.Q end end end

25

def logout end end

+ resulta o ao tentarmos e"etuar um lo#in invli o seria o se#uinteA

.m lo#in vli o nos levaria para o controller que tentamos acessar6 se=a qual "or ele. + c< i#o J bem simples. Analisan o linha a linha6 terIamos uma seqR@ncia "cil. Primeiro6 testamos se o "ormulrio est sen o submeti o. -e estiver6 tentamos encontrar um usurio que aten a Mquele lo#in e senha. Aqui voc@ po e ver um uso os mJto os find0@/automaticamente #era os. -e no encontrarmos um re#istro que aten a esses critJrios6 simplesmente ren eri>amos a mesma p#ina6 in"orman o uma mensa#em ao usurio. Caso encontremos um usurio6 porJm6 re#istramos o seu i motivos para re#istrar somente o i so na varivel a sessoK e sesso que escolhemos. +s o que ois6 se a estrutura o ob=eto

uplosA um6 J muito mais e"iciente arma>enar um nPmero

um ob=eto completo que teria que ser monta o a ca a requisio

mu ar ou6 por al#um motivo6 o Rails no encontrar a classe naquela requisio6 um erro ser #era o.

21

Ap<s re#istramos o i

o usurio6 veri"icamos se h al#um lu#ar para re irecionarmos. :estamos se e0iste

ou no um re irecionamento e6 caso e0ista6 se no J para o controller que estamos a#ora. ?sso6 mais uma ve>6 evita erros e re ire&es in"initas. -e tivermos um valor vli o6 re irecionamos para o mesmo. -e no6 meramente acessamos a p#ina inicial a aplicao. Com isso6 temos um sistema simples e "uncional e autenticao que voc@ po e aumentar e acor o com

suas necessi a es6 a icionan o autenticao se#ura6 autenticao via hashes ou qualquer outra coisa que ese=e. Botamos mais uma ve> que e0istem plu#ins para a=u ar na implementao essas tare"as. Po emos aproveitar a in"ormao que temos "acili a e ao usurio. Primeiro6 precisamos e sesso e mo i"icar o nosso la,out para ar mais uma

e um helper para nos

ar o usurio autentica o no momento.

Po emos colocar isso no helper #lobal a aplicao6 mo i"ican o o arquivo application0helpers.rbA

module Lppli ation;elper def ye"AorAnoU%value( value U QFe"Q : Q8oQ end def "e""ionAu"er @"e""ionAu"er MM! O"er.find%:fir"tJ : ondition" !. )Hid ! UHJ "e""ion):u"er++( end end

A tJcnica acima J um emonstrao o que h e melhor o Rub,. Dueremos retornar o ob=eto associa o ao usurio autentica o. Po e acontecer e termos que usar esse ob=eto mais e um ve>. 7a>er um requisio no banco to a ve> em que precisarmos o ob=eto seria bem ine"iciente. + que "a>emos ento J criar uma varivel primeiro que no "or nulo. Como retorno ser o e instLncia que contenha o ob=eto retorna o. A sinta0e acima e sesso ser nula6 o

si#ni"ica que retornamos a varivel e instLncia ou S^^T o valor a chama a ao mJto o find a classe Aser6 o a primeira ve> que a chama a "or "eita a varivel a chama a. (as6 nesse momento6 atribuImos S^^_T o valor retorna o M varivel6 que ser

ento retorna o em to as as ve>es subseqRentes. Bote que usamos find com :first /para evitarmos um erro caso o usurio no e0ista. Besse caso6 queremos somente que um valor nulo se=a a o quan o a sesso no e0istir6 ao contrrio e um erro. A#ora6 mo i"icamos o la,out a aplicao6 em app/!iews/layouts/application.rhtmlA

K,tml. K,ead. Ktitle.X<GK/title. KY! "tyle",eetAlin#Atag QdefaultQ Y.

2!

KY! "tyle",eetAlin#Atag Q" affoldQ Y. K/,ead. Kbody. K,1 id!Q,eaderQ.X<GK/,1. KY if "e""ionAu"er Y. Kp id!Qlogin-informationQ. Fou are logged in a" K"trong.KY! "e""ionAu"er.name Y.K/"trong.. KY! lin#Ato QDog outQJ : ontroller !. QloginQJ :a tion !. QlogoutQ Y.. K/p. KY end Y. Kul id!QmenuQ. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 4ontext"QJ : ontroller !. Q ontext"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 =ro-e t"QJ : ontroller !. Qpro-e t"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 L tion"QJ : ontroller !. Qa tion"QJ :a tion !. Qli"tQ Y.K/li. K/ul. Kdiv id!Q ontent"Q.KY! yield Y.K/div. K/body. K/,tml.

Por

"im6

acrescentamos

se#uinte

"ra#mento

estilo

st,lesheet

aplicao

em

public/stylesheets/default.cssA

?login-information S po"ition: ab"olute5 rig,t: 1'px5 top: 5px5 margin: '5 padding: '5 font-"ize: "mall5 T

+ resulta o J esseA

25

Po emos a#ora implementar a ao que remove a sesso o usurio6 que J bem simplesA

la"" Dogin4ontroller K Lppli ation4ontroller "#ipAbeforeAfilter :aut,enti ateJ :only !. ):login+ def login if re@ue"t.po"tU @u"er ! O"er.findAbyAloginAandApa""word%param"):login+J param"):pa""word+( if @u"er "e""ion):u"er+ ! @u"er.id if "e""ion):returnAto+ [[ W"e""ion):returnAto+.in ludeU%urlAfor%:a tion !. QloginQ(( redire tAto "e""ion):returnAto+ "e""ion):returnAto+ ! nil el"e redire tAto : ontroller !. Q,omeQ end el"e fla",):noti e+ ! Q7nvalid login and/or pa""word.Q end end end def logout "e""ion):u"er+ ! nil end end

(o i"icamos tambJm nossa vieG Sapp/!iews/login/logout.rhtmlTA

K,1.DogoutK/,1. Kp.<,an#" for ,aving u"ed t,i" "ite.K/p.

22

/ o resulta o e sair a aplicao JA

7iltros tambJm po em ser usa os em mPltiplas combina&es. Para mo elo e a os e usurios para incluir tambJm o conceito Pnicos que po em ca astrar novos usurios. Comeamos #eran o uma mi#raoA

emonstrar isso6 vamos e0pan ir o o sistema6 que sero os

e a ministra ores

ronaldo@minerva:~/tmp/gtd$ " ript/generate migration addAadmini"trativeAu"er" reate db/migrate reate db/migrate/''*AaddAadmini"trativeAu"er".rb

/ e itan o a mesmaA

la"" LddLdmini"trativeO"er" K L tive2e ord::Bigration def "elf.up addA olumn :u"er"J :adminJ :boolean O"er.re"etA olumnAinformation O"er.findAbyAname%QronaldoQ(.toggleW%QadminQ( end def "elf.down removeA olumn :u"er"J :admin end end

Como no temos atJ a#ora uma a ministrao

e usurios6 po emos cri;la6 se#uin o o pa ro

os outros

1$$

controllers que temos. -e voc@ #erou esse controller anteriormente6 o resulta o "inal eve ser assemelhar a
al#o assimA

Lembre;se e alterar o arquivo application.rhtml em app/!iews/layouts para re"letir o novo menu. Como a rea e usurio somente po e ser acessar por usurios a ministrativos6 precisamos e uma "orma

e recusar acesso M mesma caso o usurio no tenha esse per"il. 7aremos isso com o uso e um "iltro e0tra6 aplicvel somente aos controllers que estiverem sob

a ministrao6 que6 no momento6 J somente o pr<prio controller e usurios. /ntretan o6 como o "iltro po e ser aplica o a mais e um controller ei0aremos sua e"inio no controller rai>6 application.rbA

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :aut,enti ate prote ted def aut,enti ate unle"" "e""ion):u"er+ "e""ion):returnAto+ ! re@ue"t.re@ue"tAuri redire tAto : ontroller !. QloginQJ :a tion !. QloginQ return fal"e end return true end def aut,enti ateAadmini"tration unle"" "e""ionAu"er [[ "e""ionAu"er.adminU

1$1

redire tAto :a tion !. Qa return fal"e end return true end end

e""AdeniedQ

A i Jia J simplesA se houver acesso a ministrativo6 "iltro ao controller e usuriosA

ei0amos a ao continuarK caso contrrio6

re irecionamos para uma ao que in"orma que o acesso "oi ne#a o. A#ora6 precisamos somente aplicar o

la"" O"er"4ontroller K Lppli ation4ontroller beforeAfilter :aut,enti ateAadmini"tration def index li"t render :a tion !. Qli"tQ end def li"t @u"erApage"J @u"er" ! paginate :u"er"J :perApage !. 5J :order !. QnameQ end def edit if param"):id+ @u"er ! O"er.find%param"):id+( el"e @u"er ! O"er.new end if re@ue"t.po"tU @u"er.attribute" ! param"):u"er+ if @u"er."ave fla",):noti e+ ! Q<,e u"er wa" "u redire tAto :a tion !. Qli"tQ end end end def delete O"er.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e u"er wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully "avedQ

e""fully deletedQ

Ao carre#armos o controller e usurio6 veremos que um erro acontece6 = que o mJto o session0user no e0iste nem nesse controller nem no controller rai>6 estan o presente somente no helper. A soluo J pelo pr<prio RailsA movemos o mJto o o helper para o controller e o manten o o acesso ao mesmo nas vieGs. + resulta o "inal6 epois e movermos o mJto o J o se#uinteA a a eclaramos l como um helper6

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :aut,enti ate ,elperAmet,od :"e""ionAu"er prote ted

1$*

def "e""ionAu"er @"e""ionAu"er MM! O"er.find%:fir"tJ : ondition" !. )Hid ! UHJ "e""ion):u"er++( end def aut,enti ate unle"" "e""ion):u"er+ "e""ion):returnAto+ ! re@ue"t.re@ue"tAuri redire tAto : ontroller !. QloginQJ :a tion !. QloginQ return fal"e end return true end def aut,enti ateAadmini"tration unle"" "e""ionAu"er [[ "e""ionAu"er.adminU redire tAto :a tion !. Qa e""AdeniedQ return fal"e end return true end end

Precisamos a#ora somente

e uma mo i"icao em nosso arquivo

e la,out para re"letir os ca astros que

no esto acessIveis a usurios comunsA

K,tml. K,ead. Ktitle.X<GK/title. KY! "tyle",eetAlin#Atag QdefaultQ Y. KY! "tyle",eetAlin#Atag Q" affoldQ Y. K/,ead. Kbody. K,1 id!Q,eaderQ.X<GK/,1. KY if "e""ionAu"er Y. Kp id!Qlogin-informationQ. Fou are logged in a" K"trong.KY! "e""ionAu"er.name Y.K/"trong.. KY! lin#Ato QDog outQJ : ontroller !. QloginQJ :a tion !. QlogoutQ Y.. K/p. KY end Y. Kul id!QmenuQ. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 4ontext"QJ : ontroller !. Q ontext"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 =ro-e t"QJ : ontroller !. Qpro-e t"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 L tion"QJ : ontroller !. Qa tion"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 2e"our e"QJ : ontroller !. Qre"our e"QJ :a tion !. Qli"tQ Y.K/li. KY if "e""ionAu"er [[ "e""ionAu"er.adminU Y. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 O"er"QJ : ontroller !. Qu"er"QJ :a tion !. Qli"tQ Y.K/li. KY end Y. K/ul. Kdiv id!Q ontent"Q.KY! yield Y.K/div. K/body. K/,tml.

1$'

Acessan o com um usurio a ministra or6 terIamosA

/ com um usurio que no se=a a ministra orA

1$4

-e a#ora6 com um usurio no a ministrativo6 tentarmos acessar um controller que

everia ser somente

para o outro per"il6 teremos um re irecionamento. ?sso acontece porque a ao que "a> a ne#ao e acesso tambJm est su=eita ao "iltro. Resolvemos isso com a se#uinte mu ana em nosso controller primrioA

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :aut,enti ate "#ipAbeforeAfilter :aut,enti ateAadmini"trationJ :only !. ):a ,elperAmet,od :"e""ionAu"er prote ted def "e""ionAu"er @"e""ionAu"er MM! O"er.find%:fir"tJ : ondition" !. )Hid ! UHJ "e""ion):u"er++( end def aut,enti ate unle"" "e""ion):u"er+ "e""ion):returnAto+ ! re@ue"t.re@ue"tAuri redire tAto : ontroller !. QloginQJ :a tion !. QloginQ return fal"e end return true end def aut,enti ateAadmini"tration unle"" "e""ionAu"er [[ "e""ionAu"er.adminU redire tAto :a tion !. Qa e""AdeniedQ return fal"e end return true end end e""Adenied+

Bote que os "iltros cria os "oram aplica os em sua or em o mesmo.

eclarao6 partin o

o "iltro presente no

controller base e que po emos e0cluir um "iltro para etermina as a&es mesmo antes e eclararmos o uso

Precisamos a#ora apenas criar a nossa ao accessY enie . Como essa J uma ao que ser compartilha a por to os os controllers6 tambJm vamos e"inila no mesmo arquivoA

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :aut,enti ate "#ipAbeforeAfilter :aut,enti ateAadmini"trationJ :only !. ):a ,elperAmet,od :"e""ionAu"er def a e""Adenied render :template !. Q",ared/a end prote ted def "e""ionAu"er @"e""ionAu"er MM! O"er.find%:fir"tJ : ondition" !. )Hid ! UHJ "e""ion):u"er++( e""AdeniedQ e""Adenied+

1$5

end def aut,enti ate unle"" "e""ion):u"er+ "e""ion):returnAto+ ! re@ue"t.re@ue"tAuri redire tAto : ontroller !. QloginQJ :a tion !. QloginQ return fal"e end return true end def aut,enti ateAadmini"tration unle"" "e""ionAu"er [[ "e""ionAu"er.adminU redire tAto :a tion !. Qa e""AdeniedQ return fal"e end return true end end

Bote que estamos usan o um template compartilha o tambJm. Precisamos isso porque6 como menciona o anteriormente6 o Rails acha vieGs pelo controller. .san o o mJto o acima6 #arantimos que o mesmo arquivo sempre ser chama o. De"inimos a#ora o arquivo6 que "icar o para o se#uinteA iret<rio app/!iews/shared6 com o nome access0denied.rhtml6

K,1.L

e"" GeniedK/,1. e"" to t,i" page.K/p.

Kp.>orryJ you donHt ,ave a

+ resulta o6 com um usurio que no tenha acesso6 J o se#uinteA

Dualquer p#ina a ministrativa a#ora po eria "a>er uso

o "iltro6 sem precisar se preocupar em

e"inir a

1$1

sua pr<pria ao ou sua pr<pria vieG. Aqui vamos que to os os conceitos "uncionam no Rails e que o "rameGor86 ao contrrio e"ini&es M parte a lin#ua#em. Bossa aplicao a#ora contJm um mecanismo bsico implementao e mais coisas interessantes na mesma.

o mo elo orienta o a ob=etos esenvolve or com

e muitos6 no pre=u ica o

e autenticao e po emos continuar na

UPLOADS
.ma as coisas que po emos "a>er e arquivos. e maneira relativamente simples com o Rails J #erenciar o uploa e

oGnloa

/m uma aplicao como a nossa6 ca a ao po eria6 por e0emplo6 estar associa a a um ou mais arquivos. 7a> senti o pensar tambJm que um arquivo po e estar associa o a mais po e precisar e um sobre a mesma. ?sso implicaria em um #erencia or e associ;los com nossas a&es. A primeira coisa que temos que "a>er a#ora6 ento6 J criar uma maneira aplicao. Para isto6 vamos comear com o nosso mo elo e a osA e enviar arquivos para a nossa e uma aoA por e0emplo6 voc@ ocumento para elaborar uma proposta e tambJm para conversar com o seu cliente e arquivos ou recursos em nossa aplicao e um mo o

ronaldo@minerva:~/tmp/gtd$ " ript/generate model re"our e exi"t" app/model"/ exi"t" te"t/unit/ exi"t" te"t/fixture"/ reate app/model"/re"our e.rb reate te"t/unit/re"our eAte"t.rb reate te"t/fixture"/re"our e".yml exi"t" db/migrate reate db/migrate/''RA reateAre"our e".rb

/ e itar a mi#rao para #erar a nossa tabela correspon enteA

la"" 4reate2e"our e" K L tive2e ord::Bigration def "elf.up reateAtable :re"our e" do MtM t. olumn :nameJ :"tring t. olumn :filenameJ :"tring end end def "elf.down dropAtable :re"our e" end end

Bo comeo6 precisamos somente e arma>enar o nome o recurso e o nome o seu arquivo. -e precisarmos e mais al#uma coisa6 sempre po emos voltar e corri#ir o nosso mo elo com uma nova mi#rao

1$!

Precisamos a#ora e um controller para "a>er o ca astro e nossos recursosA

ronaldo@minerva:~/tmp/gtd$ " ript/generate ontroller re"our e" index li"t edit delete exi"t" app/ ontroller"/ exi"t" app/,elper"/ reate app/view"/re"our e" exi"t" te"t/fun tional/ reate app/ ontroller"/re"our e"A ontroller.rb reate te"t/fun tional/re"our e"A ontrollerAte"t.rb reate app/,elper"/re"our e"A,elper.rb reate app/view"/re"our e"/index.r,tml reate app/view"/re"our e"/li"t.r,tml reate app/view"/re"our e"/edit.r,tml reate app/view"/re"our e"/delete.r,tml

.ma mo i"icao rpi a em nosso mo elo #arante a nossa vali ao e a osA

la"" 2e"our e K L tive2e ord::/a"e validate"Apre"en eAof :name validate"Apre"en eAof :filename end

Po emos e itar os arquivos para che#ar ao mesmo pa ro que nossos

emais6 mo i"ican o apenas o que

precisamos. Primeiro6 a icionamos mais uma rea em nosso menu principalA

K,tml. K,ead. Ktitle.X<GK/title. KY! "tyle",eetAlin#Atag QdefaultQ Y. KY! "tyle",eetAlin#Atag Q" affoldQ Y. K/,ead. Kbody. K,1 id!Q,eaderQ.X<GK/,1. KY if "e""ionAu"er Y. Kp id!Qlogin-informationQ. Fou are logged in a" K"trong.KY! "e""ionAu"er.name Y.K/"trong.. KY! lin#Ato QDog outQJ : ontroller !. QloginQJ :a tion !. QlogoutQ Y.. K/p. KY end Y. Kul id!QmenuQ. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 4ontext"QJ : ontroller !. Q ontext"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 =ro-e t"QJ : ontroller !. Qpro-e t"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 L tion"QJ : ontroller !. Qa tion"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 2e"our e"QJ : ontroller !. Qre"our e"QJ :a tion !. Qli"tQ Y.K/li. KY if "e""ionAu"er [[ "e""ionAu"er.adminU Y. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 O"er"QJ : ontroller !. Qu"er"QJ :a tion !. Qli"tQ Y.K/li. KY end Y. K/ul. Kdiv id!Q ontent"Q.KY! yield Y.K/div.

1$5

K/body. K/,tml.

A#ora po emos criar o controller a e0emplo os outrosA

la"" 2e"our e"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @re"our eApage"J @re"our e" ! paginate :re"our e"J :perApage !. 5J :order !. QnameQ end def edit if param"):id+ @re"our e ! 2e"our e.find%param"):id+( el"e @re"our e ! 2e"our e.new end if re@ue"t.po"tU @re"our e.attribute" ! param"):re"our e+ if @re"our e."ave fla",):noti e+ ! Q<,e re"our e wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def delete 2e"our e.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e re"our e wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

/ tambJm uma p#ina para lista#emA

K,1.2e"our e"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew 2e"our eQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.9ileK/t,. Kt,.L tion"K/t,. K/tr. KY @re"our e".ea , do Mre"our eM Y. Ktr. Ktd.KY! re"our e.name Y.K/td. Ktd.KY! re"our e.filename Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. re"our e Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. re"our e TJ : onfirm !. QLre you "ureUQ Y. K/td.

1$2

K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@re"our eApage"( Y.K/p.

Por "im6 uma vieG bsica para e ioA

K,1.KY if @re"our e.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. 2e"our eK/,1. KY! errorAme""age"Afor Qre"our eQ Y. KY! "tartAformAtag%S:a tion !. QeditQJ :id !. @re"our eTJ S:multipart !. trueT( Y. Kp. Klabel for!Qre"our eAnameQ.8ame:K/label.Kbr. KY! textAfield Qre"our eQJ QnameQ Y. K/p. Kp. Klabel for!Qre"our eAfilenameQ.9ile:K/label.Kbr. KY! fileAfield Qre"our eQJ QfilenameQ Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p. KY! endAformAtag Y.

Bote

uas coisasA primeiro6 o uso

o mJto o file0field para #erar um campo

e uploa . -e#un o6 o uso

e0ten i o

o mJto o start0form0tag6 passan o um parLmetro a icional

e op&es. -em esse parLmetro6

multipart6 que #era o atributo enctype

o "ormulrio6 o "ormulrio no "ar uploa s6 envian o somente o

nome o arquivo ao invJs e seus a os. /ssa mu ana J vista abai0o6 no 4:(L #era oA

Kform a tion!Q/re"our e"/edit/Q en type!Qmultipart/form-dataQ met,od!Qpo"tQ.

:emos a#ora a se#uinte telaA

11$

-e salvarmos um re#istro6 notaremos al#umas coisas estranhasA primeiro6 nenhum arquivo J envia o para qualquer iret<rio no servi orK se#un o6 a vali ao no "uncionaK e terceiro6 o campo no banco e a os com in"orma&es estranhas6 como po emos ver na tela abai0oA

111

?sso acontece porque6 no caso responsabili a e simpli"ica a esse ob=eto.

e um uploa 6 um ob=eto especial J envia o para o controller e J

o mesmo processar esses ob=etos. + que vemos acima J uma representao te0tual

+ ob=eto )tringBC representa uma coleo arbitrria

a os binrios6 acessIveis como um strin#.

Po emos usar os mJto os esse ob=eto para salvar o nosso arquivo em isco e "a>er o que mais precisamos. A maneira mais "cil e "a>er isso J mo i"icar o mo o como o mo elo processa os a os6 manten o o uso o atributo transparente para o usurio. Para isto6 vamos mo i"icar inicialmente a vieG para #ravar em um outro atributoA

K,1.KY if @re"our e.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. 2e"our eK/,1. KY! errorAme""age"Afor Qre"our eQ Y. KY! "tartAformAtag%S:a tion !. QeditQJ :id !. @re"our eTJ S:multipart !. trueT( Y. Kp. Klabel for!Qre"our eAnameQ.8ame:K/label.Kbr. KY! textAfield Qre"our eQJ QnameQ Y. K/p. Kp. Klabel for!Qre"our eAfileQ.9ile:K/label.Kbr. KY! fileAfield Qre"our eQJ QfileQ Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p. KY! endAformAtag Y.

(o i"icaremos tambJm o mo eloA

la"" 2e"our e K L tive2e ord::/a"e attrAprote ted :filename validate"Apre"en eAof :name validate"Apre"en eAof :filename def file!%value( end end

+ c< i#o acima prote#e o atributo filename somente

e qualquer atribuio automtica e cria um novo atributo a os. :estan o o "ormulrio voc@ ver que a

e escrita chama o file que receber nossos

vali ao voltou a "uncionar embora6 obviamente6 como no estamos atribuin o na a ao atributo "ilename6 o re#istro no ser salvo. + que precisamos a#ora J veri"icar se al#um a o "oi realmente envia o e salvar em isco se "or o casoA

11*

la"" 2e"our e K L tive2e ord::/a"e attrAprote ted :filename validate"Apre"en eAof :name validate"Apre"en eAof :filename def file!%value( if value."ize . ' "elf.filename ! 9ile.ba"ename%value.originalAfilename( filepat, ! Q?S2L7D>A2::<T/publi /upload"/?S"elf.filenameTQ 9ile.open%filepat,J QwbQ( do MfM f.write%value.read( end end end end

Antes

e e0ecutar o c< i#o acima6 lembre;se

e criar um

iret<rio chama o uploads6

ebai0o

iret<rio

public6 com permiss&es e escrita e leitura apropria as para o seu sistema. Bo c< i#o6 veri"icamos inicialmente se al#um arquivo ori#inal e recolhemos somente o nome filename6 e e"etivamente vali an o o mesmo. Depois isso6 #eramos um caminho local para o arquivo basea o na varivel 1-B )01CC*6 que J interna ao e sua aplicao on e to os os iret<rio esto locali>a os. )amos iretamente em um te0to6 e interpolaoA variveis aplica as a o "oi envia o. Depois6 recuperamos o nome completo o

o arquivo em si6 sem seu caminho6 colocan o;o no atributo

Rails. /ssa varivel aponta para a rai> aqui tambJm o nosso primeiro e0emplo isco. Bote que escrever um arquivo em open

usan o o marca or #DE. 7inalmente6 escrevemos os

a os recebi os em nossa varivel para o arquivo em

isco J uma tare"a e0tremamente simples em Rails6 usan o o mJto o

a classe File6 que recebe um bloco como parLmetro6 on e as opera&es so e"etua os. /m nosso a "orma acima6 sem parLmetros in icativos e tamanho6 #ravam ou l@em tu o o que

caso aqui6 escrevemos os a os li os a varivel o tipo )tringBC recebi a. +s mJto os write e read6 caso se=am usa os receberam. Com o uso o bloco6 o arquivo J automaticamente "echa o epois e sua utili>ao. + c< i#o acima tem uma "alha "un amental no senti o que sobrescreve arquivos = envia os se o nome "or o mesmo e outro re#istro. +bviamente6 sobrescrever os a os arbitrariamente no J uma coisa que queremos. /0istem vrias "ormas e resolver isso e veremos uma elas em breve. -e voc@ testar a aplicao a#ora6 ver que po e "a>er o uploa melhorar somente a visuali>ao lista#emA e qualquer arquivo. Precisamos a#ora

o que temos. A primeira coisa J colocar um lin8 para o arquivo na

11'

K,1.2e"our e"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew 2e"our eQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.9ileK/t,. Kt,.L tion"K/t,. K/tr. KY @re"our e".ea , do Mre"our eM Y. Ktr. Ktd.KY! re"our e.name Y.K/td. Ktd.KY! lin#Ato re"our e.filenameJ Q/upload"/?Sre"our e.filenameTQ Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. re"our e Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. re"our e TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@re"our eApage"( Y.K/p.

+ resulta o vemos abai0oA

Po emos tambJm melhorar um pouco a nossa p#ina e e ioA

K,1.KY if @re"our e.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. 2e"our eK/,1.

114

KY! errorAme""age"Afor Qre"our eQ Y. KY! "tartAformAtag%S:a tion !. QeditQJ :id !. @re"our eTJ S:multipart !. trueT( Y. Kp. Klabel for!Qre"our eAnameQ.8ame:K/label.Kbr. KY! textAfield Qre"our eQJ QnameQ Y. K/p. KY unle"" @re"our e.newAre ordU Y. Kp. <,e urrent file i" KY! lin#Ato @re"our e.filenameJ Q/upload"/?S@re"our e.filenameTQ Y.. 4,oo"e a new file below to repla e it. K/p. KY end Y. Kp. Klabel for!Qre"our eAfileQ.9ile:K/label.Kbr. KY! fileAfield Qre"our eQJ QfileQ Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p. KY! endAformAtag Y.

Com o se#uinte resulta oA

)oc@ provavelmente notou que repetimos

uas ve>es o c< i#o que #era a .RL

o arquivo na aplicao.

-eria interessante e0trairmos isso em um mJto o que possa ser reusa o. 7a>emos isso em nosso mo eloA

115

la"" 2e"our e K L tive2e ord::/a"e attrAprote ted :filename validate"Apre"en eAof :name validate"Apre"en eAof :filename def file!%value( if value."ize . ' "elf.filename ! 9ile.ba"ename%value.originalAfilename( filepat, ! Q?S2L7D>A2::<T/publi /upload"/?S"elf.filenameTQ 9ile.open%filepat,J QwbQ( do MfM f.write%value.read( end end end def url Q/upload"/Q N "elf.filename unle"" "elf.filename.nilU end end

A#ora po emos usar esse atributo em nossas vieGs. Por e0emplo6 alteran o a vieG e lista#em e a osA

K,1.2e"our e"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew 2e"our eQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.9ileK/t,. Kt,.L tion"K/t,. K/tr. KY @re"our e".ea , do Mre"our eM Y. Ktr. Ktd.KY! re"our e.name Y.K/td. Ktd.KY! lin#Ato re"our e.filenameJ re"our e.url Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. re"our e Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. re"our e TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@re"our eApage"( Y.K/p.

+ mesmo po e ser "eito na vieG e e ioA

K,1.KY if @re"our e.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. 2e"our eK/,1. KY! errorAme""age"Afor Qre"our eQ Y. KY! "tartAformAtag%S:a tion !. QeditQJ :id !. @re"our eTJ S:multipart !. trueT( Y. Kp.

111

Klabel for!Qre"our eAnameQ.8ame:K/label.Kbr. KY! textAfield Qre"our eQJ QnameQ Y. K/p. KY unle"" @re"our e.newAre ordU Y. Kp. <,e urrent file i" KY! lin#Ato @re"our e.filenameJ @re"our e.url Y.. 4,oo"e a new file below to repla e it. K/p. KY end Y. Kp. Klabel for!Qre"our eAfileQ.9ile:K/label.Kbr. KY! fileAfield Qre"our eQJ QfileQ Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p. KY! endAformAtag Y.

.m outro e0cluI o

etalhe a tratar J o que "a>er quan o um arquivo J troca o. Besse caso precisamos remover o o banco. Para isso6 nossas solu&es esto to as no mo elo e a os. :rocar o arquivo J to

arquivo anti#o antes e salvar o novo. Precisamos tambJm remover o arquivo o isco quan o um re#istro J simples quanto o c< i#o abai0oA

la"" 2e"our e K L tive2e ord::/a"e attrAprote ted :filename validate"Apre"en eAof :name validate"Apre"en eAof :filename def file!%value( if value."ize . ' if "elf.filename filepat, ! Q?S2L7D>A2::<T/publi /upload"/?S"elf.filenameTQ if 9ile.exi"t"U%filepat,( 9ile.delete%filepat,( end end "elf.filename ! 9ile.ba"ename%value.originalAfilename( filepat, ! Q?S2L7D>A2::<T/publi /upload"/?S"elf.filenameTQ 9ile.open%filepat,J QwbQ( do MfM f.write%value.read( end end end def url Q/upload"/Q N "elf.filename unle"" "elf.filename.nilU end end

/ para e0cluirmos o arquivo em Rails.

isco se o re#istro "or removi o6 valos utili>ar uma outra caracterIstica

11!

CALLBACKS
Callbac8s so muito pareci os com os "iltros que vimos anteriormente6 mas se aplicam a mo elos e a os. -o mJto os que po em ser usa os para interceptar os momentos em que um ob=eto J persisti o para o banco e a os e e0ecutar al#uma ao nesse momento. -e voc@ consultar a ocumentao o ActiveRecor 6 ver que o ciclo e persist@ncia e um ob=eto que

nunca tenha si o salvo antes se#ue as se#uintes chama asA S;T save S;T vali ` S1T be"oreYvali ation S*T be"oreYvali ationYonYcreate S;T vali ate S;T vali ateYonYcreate S'T a"terYvali ation S4T a"terYvali ationYonYcreate S5T be"oreYsave S1T be"oreYcreate S;T create S!T a"terYcreate S5T a"terYsave Bo e0emplo acima6 os mJto os numera os so callbac8s6 ou se=a6 locais on e voc@ po e inter"erir no processamento as emais chama as. )oc@ po e inter"erir antes e epois a vali ao6 antes e epois o salvamento e ser to especi"Ico como quiser6 i>en o se quer "a>er isso somente na primeira ver que o

ob=eto "or salvo ou se para to as as emais ve>es em que o ob=eto "or persisti o. + mesmo J vli o para to as as outras opera&es )amos6 ento6 nos aproveitar e persist@ncia que po em se e"etua as em um ob=eto.

isso para interceptar o momento em que o ob=eto J removi oA mais

precisamento6 lo#o epois e que o mesmo tenha si o removi o. + nosso mo elo "icar assimA

la"" 2e"our e K L tive2e ord::/a"e attrAprote ted :filename validate"Apre"en eAof :name validate"Apre"en eAof :filename afterAde"troy :removeAfile def file!%value( if value."ize . ' if "elf.filename "elf.removeAfile end "elf.filename ! 9ile.ba"ename%value.originalAfilename(

115

9ile.open%"elf.filepat,J QwbQ( do MfM f.write%value.read( end end end def url Q/upload"/Q N "elf.filename unle"" "elf.filename.nilU end def filepat, Q?S2L7D>A2::<T/publi /upload"/?S"elf.filenameTQ end def removeAfile if 9ile.exi"t"U%"elf.filepat,( 9ile.delete%"elf.filepat,( end end end

?sso resolve o nosso problema. Bote que e"etuamos um pequeno re"atoramento para eliminar a necessi a e e repetir o c< i#o. Como mencionamos acima6 a maneira cui a os especiais. + Pnico problema e "a>er uploa s em Rails J bem prtica e no necessita e muitos ar a esse

o c< i#o acima J que terIamos que ser um pouco mais criteriosos e

veri"icar se al#um arquivo no est sen o sobrescrito e tratar isso. (as6 no precisamos nos trabalho. /0iste uma soluo muito mais "cil para casos e uploa s simples com esse.

PLUGINS
Plu#ins so uma "orma e aumentar a "uncionali a e o Rails sem me0er em qualquer e suas bibliotecas a lin#ua#em Rub,6 bsicas. + Rails possui um mecanismo e plu#ins to po eroso6 #raas M "le0ibili a e

que qualquer coisa po e ser mo i"ica a em sua estrutura. /0istem plu#ins6 para criar sistemas e autenticao e e vrios tipos Scomo inclusive = mencionamosTK e vali aoK plu#ins para "ormatar atas6 te0to6

plu#ins para acrescentar novos tipos

a os Ms classes6 como enumera os6 polI#onos e nPmeros

comple0os entre outrosK plu#ins para criar novas "ormas locali>an o em httpAZZplu#ins.ra rails.or#Z.

#erar 4:(L6 9(L6 e e>enas e outras tare"as que voc@ po e analisar por si pr<prio visitan o o reposit<rio

.m plu#in em particular po e a=u ar a nossa tare"a com uploa s. Chama o capa> e reali>ar to o o processo e arquivos e uploa manipula&es no arquivo. /ntre essas manipula&es incluem;se a possibili a e re imensionamentos para o Rub,T J requeri a. ?nstalar um plu#in em Rails J bem "cil. /0istem

e file0column6 ele no J s< e outras e #erao e thumbnails e

mostra o acima6 como tambJm permitir um sJrie

e ima#ens. Beste Pltimo caso6 a #em Rma#ic8 Suma biblioteca #r"ica

uas "ormasA bai0ar o arquivo

o mesmo e

escompat;lo

na pasta/!endor/plugins6 locali>a o na aplicao6 ou usar um coman o pr<prio.


112

+ coman o ireto para isso possui caracterIsticas mais avana as que incluem a possibili a e e inte#rao com o sistema e controle e verso -ubversion6 e #eralmente J a opo mais in ica a. 3ai0ar o arquivo na mo po e ser vanta=oso para pro=etos em que mu anas quer e0ercer corre&es. -e=a qual "or a sua escolha6 a sinta0e o coman o J bem simples. )oc@ po e ver a a=u a o mesmo ro an o o coman o abai0oA e verso so ri#orosamente controla as e voc@ ecis&es manual inclusive sobre os plu#ins6 pre"erin o reali>ar suas pr<prias atuali>a&es e

ronaldo@minerva:~/tmp/gtd$ " ript/plugin

Como voc@ po e ver6 ele J bem similar ao coman o #em. Para bai0ar o plu#in que precisamos aqui6 file0column6 voc@ po e usar o coman o se#uinteA

ronaldo@minerva:~/tmp/gtd$ " ript/plugin in"tall E ,ttp://open"vn. "ie.org/rail"AfileA olumn/plugin"/fileA olumn/trun#

Bo nosso caso6 eu = tenho o plu#in instala o em outro pro=eto e vou simplesmente copi;lo para o iret<rio !endor/plugins6 #eran o a se#uinte estruturaA

ronaldo@minerva:~/tmp/gtd/vendor/plugin"/fileA olumn$ l" -l total &8 -rw-r--r-- 1 ronaldo ronaldo 3&$* &''*-'6-&& 1*:36 4;L8X1D:X -rw-r--r-- 1 ronaldo ronaldo 366 &''*-'6-&& 1*:36 init.rb drwxr-xr-x & ronaldo ronaldo $'6* &''*-'6-&& 1*:$' lib -rw-r--r-- 1 ronaldo ronaldo R8& &''*-'6-&& 1*:36 2a#efile -rw-r--r-- 1 ronaldo ronaldo 185* &''*-'6-&& 1*:36 21LGB1 drwxr-xr-x $ ronaldo ronaldo $'6* &''*-'6-&& 1*:$' te"t -rw-r--r-- 1 ronaldo ronaldo &$3 &''*-'6-&& 1*:36 <:G:

)oc@ po e e0plorar o carre#a o pelo Rails.

iret<rio para visuali>ar a or#ani>ao interna

o plu#in e enten er como o Rails

conse#ue in enti"ic;lo e incorpor;lo. Lembre;se a#ora

e reiniciar o servi or para que o plu#in se=a

A#ora que temos esse plu#in6 po emos us;lo em nosso c< i#o. Bosso mo elo ser substituI o porA

la"" 2e"our e K L tive2e ord::/a"e validate"Apre"en eAof :name validate"Apre"en eAof :filename fileA olumn :filename end

1*$

eclarao file0column vem

iretamente

o plu#in e #era uma sJrie

e mJto os e atributos que

po emos utili>ar transparentemente em nossa aplicao. -e voc@ testou a vali ao com a nossa verso anterior o mo elo e a os e as vieGs ter percebi o que quan o o nome o ob=eto no J in"orma o6 causan o uma vali ao6 qualquer arquivo in"orma o ser o nosso plu#in6 ele toma conta isso per i o6 e0i#in o que o usurio o in"orme mais uma ve>. Bo caso

arma>enan o o arquivo temporariamente para que o usurio no tenha que conviver com um comportamento an[malo e nem e0i#in o que o esenvolve or se preocupe com etalhes como esses. )amos mo i"icar a#ora nossa vieG e e io paraA

K,1.KY if @re"our e.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. 2e"our eK/,1. KY! errorAme""age"Afor Qre"our eQ Y. KY! "tartAformAtag%S:a tion !. QeditQJ :id !. @re"our eTJ S:multipart !. trueT( Y. Kp. Klabel for!Qre"our eAnameQ.8ame:K/label.Kbr. KY! textAfield Qre"our eQJ QnameQ Y. K/p. KY unle"" @re"our e.newAre ordU Y. Kp. <,e urrent file i" KY! lin#Ato @re"our e.ba"eAfilenameJ urlAforAfileA olumn%Qre"our eQJ QfilenameQ( Y.. 4,oo"e a new file below to repla e it. K/p. KY end Y. Kp. Klabel for!Qre"our eAfilenameQ.9ile:K/label.Kbr. KY! fileA olumnAfield Qre"our eQJ QfilenameQ Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p. KY! endAformAtag Y.

/ nossa vieG e lista#em paraA

K,1.2e"our e"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew 2e"our eQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q Ktr. Kt,.8ameK/t,. Kt,.9ileK/t,. Kt,.L tion"K/t,. ell"pa ing!Q1Q.

1*1

K/tr. KY @re"our e".ea , do Mre"our eM Y. Ktr. Ktd.KY! re"our e.name Y.K/td. Ktd. KY! lin#Ato re"our e.ba"eAfilenameJ urlAforAfileA olumn%re"our eJ QfilenameQ( Y. K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. re"our e Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. re"our e TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@re"our eApage"( Y.K/p.

Pelo "ato

o plu#in no ter nenhum mJto o para retornar simplesmente o nome

o arquivo6 intro u>imos a

mu ana acima na vieG e criamos o mJto o base0filename6 que voc@ po e ver abai0oA

la"" 2e"our e K L tive2e ord::/a"e validate"Apre"en eAof :name validate"Apre"en eAof :filename fileA olumn :filename def ba"eAfilename 9ile.ba"ename%"elf.filename( end end

Como o c< i#o

o plu#in J aberto6 po erIamos ter corri#i o essas

e"ici@ncia

iretamente no mesmo e inLmicos o Rub,6 e tocar o

provavelmente ela ser sana a em al#uma verso "utura. Alis6 com os recursos po erIamos ter intro u>i o o mJto o c< i#o. (esmo com esse pequeno problema6 porJm6 po emos ver que o uso substancialmente o trabalho manti o. Consi ere6 por e0emplo6 uma aplicao com por n<s. )e=a que os arquivos esto em um e0emplo na lista#em abai0oA iret<rio sob public6 cu=o nome J a classe entro esse iret<rio6 um ouro e e>enas

iretamente nas classes envolvi as sem necessi a es

e plu#ins po e re u>ir e ser e e uploa . Ao invJs

o pro#rama or e a=u ar o c< i#o a "icar mais limpo e mais "cil e necessi a es

termos que li ar atributo por atributo com o problema6 po emos simplesmente ei0ar que o plu#in "aa isso

a os6 com um

iret<rio

para ca a atributo controla o pelo plu#in e6

iret<rio por ob=eto. )e=a um

ronaldo@minerva:~/tmp/gtd/publi /re"our e/filename/R$ l" babel.do

(uito simples e intuitivo. Caso voc@ queira controlar os arquivos com maior ri#or6 autentican o o acesso aos
1**

mesmos6 por e0emplo6 voc@ po eria mu ar o abai0oA

iret<rio on e os mesmos so arma>ena os usan o o c< i#o

fileA olumn :filenameJ :"toreAdir !. Q/upload"/re"our e"/filename/Q

-eria i"Icil conse#uir al#o mais simples o que isso. A#ora que temos os nossos recursos6 po emos associa&es entre associa&es has0and0belongs0to0many. emonstrar mais uma caracterIstica o Rails6 que so as

uas classes interme ia as por outra classe6 menciona as mais acima no te0toA

HAS AND BELONGS TO MANY


Associa&es has0and0belongs0to0many so o resulta o e relacionamentos B para B entre uas tabelas em um banco e a os. + Rails J per"eitamente capa> e representar esse tipo e associao ou relacionamento e uma maneira muito similar M "eita com has0many. /ssas associa&es so tabela real entre os i"erentes as associa&es has0many usan o throu#h no senti o que e0iste uma

ois mo elos enquanto que nesta Pltima o mo elo interme irio J usa o somente para

colapsar os a os em uma a#re#ao. Como temos uma tabela interme iria representan o a relao6 o Rails tambJm se#ue uma conveno. A tabela eve se nomea a como a unio entre os nomes os ois mo elos que lhe o ori#em6 em or em isco ser chama a al"abJtica. Bo nosso caso6 a tabela que relaciona as a&es aos recursos em actions0resources. Bote o plural nos nomes. .m etalhe interessante J que caso essa tabela contenha outros campos6 eles sero re"leti os e c< i#o a icional. /6 mais o que isso6 no J necessrio

automaticamente na associao sem necessi a e #erar qualquer mo elo. )amos partir ento para a mi#rao necessriaA

ronaldo@minerva:~/tmp/gtd$ " ript/generate migration reateAa tion"Are"our e" reate db/migrate reate db/migrate/''8A reateAa tion"Are"our e".rb

/ a e itamosA

la"" 4reateL tion"2e"our e" K L tive2e ord::Bigration def "elf.up reateAtable :a tion"Are"our e"J :id !. fal"e do MtM t. olumn :a tionAidJ :integer t. olumn :re"our eAidJ :integer

1*'

end end def "elf.down dropAtable :a tion"Are"our e" end end

Como no precisamos e uma coluna automtica i 6 in"ormamos M mi#rao que isso po e ser i#nora o. A#ora6 po emos mo i"ica os nossos mo elos. (o i"icaremos ambos porque po emos utili>ar a relao nas uas ire&es. Comeamos com o mo elo para as a&esA

la"" L tion K L tive2e ord::/a"e attrAprote ted : reatedAatJ : ompletedAat def done!%value( if L tive2e ord::4onne tionLdapter"::4olumn.valueAtoAboolean%value( "elf. ompletedAat ! Gate<ime.now el"e "elf. ompletedAat ! nil end writeAattribute%QdoneQJ value( end belong"Ato : ontext belong"Ato :pro-e t validate"Apre"en eAof :de" ription validate"Apre"en eAof : ontextAid validate"Apre"en eAof :pro-e tAid ,a"AandAbelong"AtoAmany :re"our e" end

/ epois passamos para o mo elo que representa recursosA

la"" 2e"our e K L tive2e ord::/a"e validate"Apre"en eAof :name validate"Apre"en eAof :filename fileA olumn :filename def ba"eAfilename 9ile.ba"ename%"elf.filename( end ,a"AandAbelong"AtoAmany :a tion" end

.san o o console a#ora6 po emos manipular essas associa&es para enten emos um pouco melhor como

1*4

elas "uncionamA

ronaldo@minerva:~/tmp/gtd$ " ript/ on"ole Doading development environment. .. a tion ! L tion.find%1( !. ?KL tion:'xbRR8a6R8 @attribute"!SQ ontextAidQ!.Q1QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.Q3QJ QdoneQ!.Q'QJ QidQ!.Q1QJ Qde" riptionQ!.Q/uy a grammar to ,elp me wit, my 1ngli",.QJ Q reatedAatQ!.Q&''*-'6-&& '6:16:3RQT. .. a tion.re"our e" !. )+

Como po emos ver6 nossa associao = est "uncionan o. :estan o um pouco maisA

.. a tion.re"our e" KK 2e"our e.find%R( !. )?K2e"our e:'xbRR3 ef8 @attribute"!SQnameQ!.Q/abelQJ QidQ!.QRQJ QfilenameQ!.Qbabel.do QT.+ .. a tion.re"our e" KK 2e"our e.find%8( !. )?K2e"our e:'xbRR3 ef8 @attribute"!SQnameQ!.Q/abelQJ QidQ!.QRQJ QfilenameQ!.Qbabel.do QT.J ?K2e"our e:'xbRR&fd68 @attribute"!SQnameQ!.Q9ir"t 9loorQJ QidQ!.Q8QJ QfilenameQ!.Q1"t-floor.pngQT.+ .. a tion.re"our e"."ize !. &

Como temos a associao o outro la o6 po emos ver que a relao J simplesA

.. re"our e ! 2e"our e.find%R( !. ?K2e"our e:'xbRRe83 @attribute"!SQnameQ!.Q/abelQJ QidQ!.QRQJ QfilenameQ!.Qbabel.do QT. .. re"our e.a tion" !. )?KL tion:'xbRRa6 f8 @attribute"!SQ ontextAidQ!.Q1QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.Q3QJ QdoneQ!.Q'QJ Qre"our eAidQ!.QRQJ QidQ!.Q1QJ Qde" riptionQ!.Q/uy a grammar to ,elp me wit, my 1ngli",.QJ Qa tionAidQ!.Q1QJ Q reatedAatQ!.Q&''*-'6-&& '6:16:3RQT.+

Bo caso

e associa&es com atributos na relao6 e0iste um mJto o especial que po e ser usa o para os mesmos. -uponha um relao entre uma tabela representan o um pe i o e uma o pe i o que se relaciona a um pro uto. +bviamente6 no item o pe i o o momento em que o pe i o "oi #era o. Po erIamos ter

a icionar os valores

tabela representan o um item

terIamos a quanti a e pe i a e o preo unitrio

um c< i#o similar ao abai0o para carre#ar um novo item em nosso pe i oA

order ! :rder.find%param"):orderAid+( produ t ! =rodu t.find%param"):produ tAid+( order.item".pu",Awit,Aattribute"%produ tJ :pri e !. produ t.pri eJ :@uantity !. 1(

Com o c< i#o abai0o6 a tabela items no banco

a os receberia um novo re#istro com os campos

order0id e product0id = con"i#ura os para os valores pr<prios os ob=etos relaciona os e com os campos price an quantity carre#a os com o valores passa os e0plicitamente para o mJto o. .ma ve> "eito isso6 os atributos po eriam ser e ita os com maior simplici a eA
1*5

order.item")'+.@uantity ! & order."ave

Como voc@ po e ver6 o relacionamento J re"leti o intituivamente no mo elo

a os sem necessi a e

qualquer es"oro a icional. Para to a a "uncionali a e #era a6 precisamos apenas e uas linhas e c< i#o. A ocumentao escreve uma sJrie e outros mJto os e parLmetros que po em ser usa os para li ar com

as situa&es mais inusita as que voc@ tiver. -e quisermos6 por e0emplo6 or enar nossas associa&es6 po emos mu ar um e nossos mo elos paraA

la"" L tion K L tive2e ord::/a"e attrAprote ted : reatedAatJ : ompletedAat def done!%value( if L tive2e ord::4onne tionLdapter"::4olumn.valueAtoAboolean%value( "elf. ompletedAat ! Gate<ime.now el"e "elf. ompletedAat ! nil end writeAattribute%QdoneQJ value( end belong"Ato : ontext belong"Ato :pro-e t validate"Apre"en eAof :de" ription validate"Apre"en eAof : ontextAid validate"Apre"en eAof :pro-e tAid ,a"AandAbelong"AtoAmany :re"our e"J :order !. QnameQ end

Para aproveitarmos essas mu anas em nosso mo elo6 vamos trabalhar mais uma ve> com o controller que #erencia o ca astro ca a ve>. Comeamos6 esta ve>6 mo i"ican o a ao e lista#em as a&esA e a&es. + nosso ob=etivo a#ora J permitir que o usurio associe recursos e arquivos e a uma ao qualquer. Para isto6 teremos um ca astro interno que nos permitir mPltiplas associa&es

K,1.L tion"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew L tionQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q Ktr. Kt,.Ge" riptionK/t,. Kt,.4ompletedK/t,. ell"pa ing!Q1Q.

1*1

Kt,.0,enK/t,. Kt,.=ro-e tK/t,. Kt,.4ontextK/t,. Kt,.L tion"K/t,. K/tr. KY @a tion".ea , do Ma tionM Y. Ktr. Ktd.KY! a tion.de" ription Y.K/td. Ktd.KY! ye"AorAnoU%a tion.doneU( Y.K/td. Ktd.KY! %a tion.doneU( U a tion. ompletedAat."trftime%QYm/Yd/YyQ( : Q-Q Y.K/td. Ktd.KY! a tion.pro-e t.name Y.K/td. Ktd.KY! a tion. ontext.name Y.K/td. Ktd nowrap. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. a tion Y. orKbr. KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. a tion TJ : onfirm !. QLre you "ureUQ Y. orKbr. KY! lin#Ato Q1dit 2e"our e"QJ :a tion !. Qre"our e"QJ :id !. a tion Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@a tionApage"( Y.K/p.

/ em se#ui a o controller as a&esA

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end if re@ue"t.po"tU @item.attribute" ! param"):item+ if @item."ave fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def re"our e" @a tion ! L tion.find%param"):id+( end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

1*!

Com essa varivel6 = po emos criar uma vieG que inicialmente e0ibe os recursos associa os com um aoA

K,1.L tion 2e"our e"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp. K"trong.L tion Ge" ription:K/"trong.Kbr. KY! @a tion.de" ription Y. K/p. K,3.2e"our e"K/,3. KY if @a tion.re"our e"."ize . ' Y. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.9ileK/t,. Kt,.L tion"K/t,. K/tr. KY @a tion.re"our e".ea , do Mre"our eM Y. Ktr. Ktd.KY! re"our e.name Y.K/td. Ktd. KY! lin#Ato re"our e.ba"eAfilenameJ urlAforAfileA olumn%re"our eJ QfilenameQ( Y. K/td. Ktd. KY! lin#Ato QGeleteQJ S :a tion !. QdeleteAre"our eQJ :id !. @a tionJ :re"our eAid !. re"our e TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table. KY el"e Y. Kp.Kem.8o re"our e wa" added to t,i" a tion yet.K/em.K/p. KY end Y.

+ resulta o JA

1*5

Precisamos para issoA

e uma "orma

e buscar as a&es que queremos associar. Po emos usar um "ormulrio simples

K,1.L tion 2e"our e"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp. K"trong.L tion Ge" ription:K/"trong.Kbr. KY! @a tion.de" ription Y. K/p. K,3.2e"our e"K/,3. KY if @a tion.re"our e"."ize . ' Y. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.9ileK/t,. Kt,.L tion"K/t,. K/tr. KY @a tion.re"our e".ea , do Mre"our eM Y. Ktr. Ktd.KY! re"our e.name Y.K/td. Ktd. KY @re"our e ! re"our e Y. KY! lin#Ato re"our e.ba"eAfilenameJ urlAforAfileA olumn%Qre"our eQJ QfilenameQ( Y. K/td. Ktd. KY! lin#Ato QGeleteQJ S :a tion !. QdeleteAre"our eQJ :id !. @a tionJ :re"our eAid !. re"our e TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y.

1*2

K/table. KY el"e Y. Kp.Kem.8o re"our e wa" added to t,i" a tion yet.K/em.K/p. KY end Y. KY! "tartAformAtag :a tion !. Qre"our e"Q Y. K,3.>ear , for 2e"our e" to LddK/,3. Kp. Klabel for!Q#eyword"Q.Ieyword":K/label.Kbr. KY! textAfieldAtag Q#eyword"QJ param"):#eyword"+ Y. K/p. Kp. KY! "ubmitAtag Q>ear ,Q Y. K/p. KY! endAformAtag Y. KY if @re"our e"."ize . ' Y. KY! "tartAformAtag :a tion !. QaddAre"our e"QJ :id !. @a tion Y. Kp.K"trong.2e"ult"K/"trong.K/p. Kul la""!Q"ear ,-re"ult"Q. KY @re"our e".ea , do Mre"our eM Y. Kli. KY! ,e #AboxAtag Qre"our e")+QJ re"our e.id Y. KY! re"our e.name Y.Kbr. K"pan.KY! lin#Ato re"our e.ba"eAfilenameJ urlAforAfileA olumn%re"our eJ QfilenameQ( Y.K/"pan. K/li. KY end Y. K/ul. Kp. KY! "ubmitAtag QLddQ Y. K/p. KY! endAformAtag Y. KY el"e Y. Kp.Kem.<,i" "ear , returned to mat ,e".K/em.K/p. KY end Y.

A#ora6 mu amos o nosso controller paraA

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T

1'$

@pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end if re@ue"t.po"tU @item.attribute" ! param"):item+ if @item."ave fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def re"our e" @a tion ! L tion.find%param"):id+( @re"our e" ! )+ if re@ue"t.po"tU [[ Wparam"):#eyword"+.blan#U @re"our e" ! 2e"our e.find%:allJ : ondition" !. )Hname li#e U or filename li#e UHJ QY?Sparam"):#eyword"+TYQJ QY?Sparam"):#eyword"+TYQ+( end end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

/ a icionamos o se#uinte "ra#mento M nossa st,lesheet pa ro6 em public/stylesheets/default.cssA

ul."ear ,-re"ult" S li"t-"tyle: none5 padding: '5 margin: '5 T ul."ear ,-re"ult" li S margin-bottom: 5px5 T ul."ear ,-re"ult" li "pan S font-"ize: "maller5 T

Com essas mu anas6 temos o se#uinte resulta oA

1'1

Precisamos a#ora realmente a icionar os recursos escolhi os M ao. Para isso6 criamos a ao que = especi"icamos na vieGA

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end

1'*

def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end if re@ue"t.po"tU @item.attribute" ! param"):item+ if @item."ave fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def re"our e" @a tion ! L tion.find%param"):id+( @re"our e" ! )+ if re@ue"t.po"tU [[ Wparam"):#eyword"+.blan#U @re"our e" ! 2e"our e.find%:allJ : ondition" !. )Hname li#e U or filename li#e UHJ QY?Sparam"):#eyword"+TYQJ QY?Sparam"):#eyword"+TYQ+( end end def addAre"our e" @a tion ! L tion.find%param"):id+( exi"tingAre"our eAid" ! @a tion.re"our e". olle t S Mre"our eM re"our e.id T newAre"our eAid" ! param"):re"our e"+.re-e t S MidM exi"tingAre"our eAid".in ludeU%id.toAi( T @a tion.re"our eAid" KK newAre"our eAid" redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

/ssa ao veri"ica os recursos e0istentes6 encontra os ain a no a iciona os Mquela ao6 os a iciona e6 por "im6 re ireciona para a lista#em mais uma ve>. )eri"icar recursos = a iciona os previne a incluso mPltiplos recursos na tabela interme iria. 7inalmente6 precisamos a ao que remove um re#istro associa o6 que J bem simplesA e

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if param"):id+

1''

@item ! L tion.find%param"):id+( el"e @item ! L tion.new end if re@ue"t.po"tU @item.attribute" ! param"):item+ if @item."ave fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end end end

e""fully "avedQ

def re"our e" @a tion ! L tion.find%param"):id+( @re"our e" ! )+ if re@ue"t.po"tU [[ Wparam"):#eyword"+.blan#U @re"our e" ! 2e"our e.find%:allJ : ondition" !. )Hname li#e U or filename li#e UHJ QY?Sparam"):#eyword"+TYQJ QY?Sparam"):#eyword"+TYQ+( end end def addAre"our e" @a tion ! L tion.find%param"):id+( exi"tingAre"our eAid" ! @a tion.re"our e". olle t S Mre"our eM re"our e.id T newAre"our eAid" ! param"):re"our e"+.re-e t S MidM exi"tingAre"our eAid".in ludeU%id.toAi( T @a tion.re"our e" KK 2e"our e.find%newAre"our eAid"( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def deleteAre"our e @a tion ! L tion.find%param"):id+( @a tion.re"our e".delete%2e"our e.find%param"):re"our eAid+(( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

Como J possIvel perceber6 o uso

e associa&es6 se=a qual "orem6 J muito simples no Rails. 7ica como

e0ercIcio para o leitor limitar a busca com base nos re#istros = e0istentes e mo o que6 para conveni@ncia o usurio6 somente re#istros ain a no a iciona os apaream.

ESCOPOS
.ma outra caracterIstica interessante o Rails6 intro u>i a na verso 1.16 J o conceito e escopo sinttico e escopos para opera&es no banco e a os. + conceito J muito similar Ms eclar&es Gith presentes em vrias lin#ua#ens e pro#ramao6 que temporariamente aumentam o nIvel "acilitan o o uso as mesmas. + uso e escopos6 a e0emplo as eclara&es Gith6 po e simplicar bastante o uso o ActiveRecor 6 mas e uma ou mais variveis6

eve ser empre#a o com cui a o por possibilitar a intro uo i"Iceis e epurar. Para emonstrar o uso

e bu#s sutis no c< i#o que po em ser bem

e escopos6 vamos "a>er al#umas altera&es em nossa aplicao6 e0pan i o a


1'4

possibili a e

e uso

o sistema por mPltiplos usurios. AtJ o momento6 qualquer usurio6 mesmo um

a ministra or6 po ia acessar to as as a&es6 conte0tos e pro=etos #era os. +bviamente6 isso no J o que queremos. Com a a=u a e escopos6 po emos resolver isso rapi amente. Primeiramente6 vamos alterar o nosso mo elo e a os6 isolan o ca a ob=eto para conter tambJm a

in"ormao o usurio que o criou. %eramos uma mi#raoA

ronaldo@minerva:~/tmp/gtd$ " ript/generate migration addAu"erAtoAob-e t" exi"t" db/migrate reate db/migrate/''6AaddAu"erAtoAob-e t".rb

/ a e itamosA

la"" LddO"er<o:b-e t" K L tive2e ord::Bigration def "elf.up addA olumn : ontext"J :u"erAidJ :integer addA olumn :pro-e t"J :u"erAidJ :integer addA olumn :a tion"J :u"erAidJ :integer addA olumn :re"our e"J :u"erAidJ :integer 4ontext.re"etA olumnAinformation =ro-e t.re"etA olumnAinformation L tion.re"etA olumnAinformation 2e"our e.re"etA olumnAinformation u"er ! O"er.findAbyAname%QronaldoQ( 4ontext.updateAall Qu"erAid ! ?Su"er.idTQ =ro-e t.updateAall Qu"erAid ! ?Su"er.idTQ L tion.updateAall Qu"erAid ! ?Su"er.idTQ 2e"our e.updateAall Qu"erAid ! ?Su"er.idTQ end def "elf.down removeA olumn removeA olumn removeA olumn removeA olumn end end : ontext"J :u"erAid :pro-e t"J :u"erAid :a tion"J :u"erAid :re"our e"J :u"erAid

Bo caso

e uma mi#rao como essa6 precisamos tambJm atuali>ar o nosso banco. / isso o que "a> essa isso6 encontramos o primeiro usurio que

mi#rao. Primeiro6 os mo elos so recarre#a os. Depois

criamos. / por "im6 utili>amos o mJto o update0all para "a>er atuali>a&es em massa em nosso re#istros. A#ora6 vamos e0perimentar com o controller responsvel pelos conte0tos6 utili>an o escopos. -e no estivJssemos usan o escopos e quisJssemos6 por e0emplo6 limitar a nossa ao list a somente re#istros um usurio6 terIamos al#o assimA e

la"" 4ontext"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t

1'5

@ ontextApage"J @ ontext" ! paginate : ontext"J : ondition" !. )Qu"erAid ! UQJ "e""ion):u"er++J :perApage !. 5J :order !. QnameQ end def edit if param"):id+ @ ontext ! 4ontext.find%param"):id+( el"e @ ontext ! 4ontext.new end if re@ue"t.po"tU @ ontext.attribute" ! param"): ontext+ if @ ontext."ave fla",):noti e+ ! Q<,e ontext wa" "u redire tAto :a tion !. Qli"tQ end end end def delete 4ontext.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e ontext wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully "avedQ

e""fully deletedQ

V uma maneira per"eitamente vli a e "a>er isso. Com escopos6 terIamosA

la"" 4ontext"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t 4ontext.wit,A" ope%:find !. S : ondition" !. )Qu"erAid ! UQJ "e""ion):u"er++ T( do @ ontextApage"J @ ontext" ! paginate : ontext"J :perApage !. 5J :order !. QnameQ end end def edit if param"):id+ @ ontext ! 4ontext.find%param"):id+( el"e @ ontext ! 4ontext.new end if re@ue"t.po"tU @ ontext.attribute" ! param"): ontext+ if @ ontext."ave fla",):noti e+ ! Q<,e ontext wa" "u redire tAto :a tion !. Qli"tQ end end end def delete 4ontext.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e ontext wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully "avedQ

e""fully deletedQ

+ mJto o with0scope recebe um sJrie e eclara&es que e"inem con i&es e atributos a serem aplica os. A princIpio po e parece mais es"oro6 mas o importante a enten er na chama a acima J que to as as
1'1

chama as ao banco

entro

o bloco usan o o mJto o find e seus

eriva os estariam su=eitas ao escopo

cria o para o mesmo6 receben o automaticamente as con i&es especi"ica as. Bo que tan#e ao mJto o find6 basicamente qualquer e seus parLmetros po e ser especi"ica o6 como o""set e limit6 por e0emplo. Alteran o a ao e it terIamos al#o assimA

la"" 4ontext"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t 4ontext.wit,A" ope%:find !. S : ondition" !. )Qu"erAid ! UQJ "e""ion):u"er++ T( do @ ontextApage"J @ ontext" ! paginate : ontext"J :perApage !. 5J :order !. QnameQ end end def edit 4ontext.wit,A" ope%:find !. S : ondition" !. )Qu"erAid ! UQJ "e""ion):u"er++ TJ : reate !. S :u"erAid !. "e""ion):u"er+ T( do if param"):id+ @ ontext ! 4ontext.find%param"):id+( el"e @ ontext ! 4ontext.new end if re@ue"t.po"tU @ ontext.attribute" ! param"): ontext+ if @ ontext."ave fla",):noti e+ ! Q<,e ontext wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end end def delete 4ontext.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e ontext wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

+ escopo aqui no s< limita a busca6 como tambJm limita a criao6 in"orman o automaticamente o atributo user0id quan o necessrio. Para impe ir que o atributo "osse automaticamente in"orma o em um "ormulrio6 precisarIamos mu ar o nosso mo elo e a osA

la"" 4ontext K L tive2e ord::/a"e attrAprote ted :u"erAid validate"Apre"en eAof :name validate"Auni@uene""Aof :name validate"Apre"en eAof :u"erAid

1'!

,a"Amany :a tion" end

Com o escopo que estabelecemos6 vemos que se um usurio tentar acessar iretamente um conte0to cria o por outro usurio6 teremos um erroA

/ vemos que6 em nosso arquivo log/de!elopment.log6 o -DL #era o continha a con io in"orma a no escopoA

1'5

=ro e""ing 4ontext"4ontroller?edit %for 1&R.'.'.1 at &''*-'6-&$ 1&:$':$5( )X1<+ >e""ion 7G: 1 381d R'663b55*'**5'*68Rd*35&18 =arameter": SQa tionQ!.QeditQJ QidQ!.Q1QJ Q ontrollerQ!.Q ontext"QT 4ontext Doad %'.''$R35( >1D14< P 92:B ontext" 0;121 %u"erAid ! &( L8G % ontext".id ! H1H( D7B7< 1

4 um pequeno problema no c< i#o acima6 porJm. -e voc@ testou a criao

e um re#istro6 ver que o

escopo no se aplicou ao mJto o sa!e6 e6 conseqRentemente6 o re#istro "oi salvo sem um atributo user0id. A e0plicao para isso po eria ser uplaA po erIamos i>er que o problema est no nosso uso e sa!e6 tanto para criao quanto para atuali>ao6 ou po erIamos tambJm i>er que h um problema no Rails6 = que6 se e0aminarmos o c< i#o ob=eto J cria o. /6 o mesmo6 veremos que o escopo no J aplica o em to as situa&es em que um e "ato6 e0istem al#uns problemas com o mJto o para os quais solu&es = "oram

propostas na base e c< i#o e esenvolvimento o Rails e po e ser estaro em suas vers&es "uturas. A soluo6 no momento6 J "a>er uma mo i"icao na ao editA

la"" 4ontext"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t 4ontext.wit,A" ope%:find !. S : ondition" !. )Qu"erAid ! UQJ "e""ion):u"er++ T( do @ ontextApage"J @ ontext" ! paginate : ontext"J :perApage !. 5J :order !. QnameQ end end def edit 4ontext.wit,A" ope%:find !. S : ondition" !. )Qu"erAid ! UQJ "e""ion):u"er++ TJ : reate !. S :u"erAid !. "e""ion):u"er+ T( do if re@ue"t.getU if param"):id+ @ ontext ! 4ontext.find%param"):id+( el"e @ ontext ! 4ontext.new end el"if re@ue"t.po"tU @ ontext ! param"):id+ U 4ontext.update%param"):id+J param"): ontext+( : 4ontext. reate%param"): ontext+( if @ ontext.validU fla",):noti e+ ! Q<,e ontext wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end en end end def delete 4ontext.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e ontext wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

+bviamente6 essa J uma soluo menos

o que i eal por e0i#ir c< i#o e0tra6 mas J o melhor que po emos
1'2

"a>er no momento. Bo c< i#o acima6 notamos que seria interessante ter o mesmo escopo aplica o a to as as a&es6 para prevenir qualquer "orma e acesso sem parLmetros. .ma soluo simples J criar um mJto o que nos retorne os escopos e aplicar isso a to os as a&es e maneira mais limpaA

la"" 4ontext"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t 4ontext.wit,A" ope%neededA" ope"( do @ ontextApage"J @ ontext" ! paginate : ontext"J :perApage !. 5J :order !. QnameQ end end def edit 4ontext.wit,A" ope%neededA" ope"( do if re@ue"t.getU if param"):id+ @ ontext ! 4ontext.find%param"):id+( el"e @ ontext ! 4ontext.new end el"if re@ue"t.po"tU @ ontext ! param"):id+ U 4ontext.update%param"):id+J param"): ontext+( : 4ontext. reate%param"): ontext+( if @ ontext.validU fla",):noti e+ ! Q<,e ontext wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end end def delete 4ontext.wit,A" ope%neededA" ope"( do 4ontext.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e ontext wa" "u redire tAto :a tion !. Qli"tQ end end prote ted def neededA" ope" @neededA" ope" MM! S :find !. S : ondition" !. )Qu"erAid ! UQJ "e""ion):u"er++ TJ : reate !. S :u"erAid !. "e""ion):u"er+ T T end end

e""fully deletedQ

/ssa soluo J bem mais le#Ivel melhor;la ain a mais6 in o

o que "icar repetin o escopos em ca a uma

as a&es6 mas po emos e

ireto M "onte. /m especial6 queremos uma soluo que possa ser aplica a a

qualquer controller que precisarmos. Como nossa aplicao J bem simples6 po emos "a>er isso atravJs um "iltro especialmente cria o para isso.

14$

.m Pnica ressalva aqui J que estamos entran o em um territ<rio no Rails on e no h uma AP? estabeleci a6 e o nosso c< i#o J su=eito a mu anas e implementao que po em quebr;lo eventualmente. (as6 no momento6 po emos apren er al#o com o que vamos "a>er.

FILTROS AROUND
Como vamos precisar e uma implementao que se=a acessIvel a to os controllers6 e e nossa aplicao e maneira #eral a to a aplicao6 precisamos coloc;la em al#um lu#ar e mo o que ela se=a carre#a a

automaticamente. Po emos "a>er isso usan o o iret<rio extras6 que J "eito especialmente para isso. Primeiro precisamos habilitar esse iret<rio em nosso arquivo config/en!ironment.rb6 que J on e as

con"i#ura&es para a aplicao esto e"ini as6 e epois incluir a chama a ao arquivo que precisamosA

? /e "ure to re"tart your web "erver w,en you modify t,i" file. ? On omment below to for e 2ail" into produ tion mode w,en ? you donHt ontrol web/app "erver and anHt "et it t,e proper way ? 18Z)H2L7D>A18ZH+ MM! Hprodu tionH ? >pe ifie" gem ver"ion of 2ail" to u"e w,en vendor/rail" i" not pre"ent 2L7D>AX1BAZ12>7:8 ! H1.1.*H ? /oot"trap t,e 2ail" environmentJ framewor#"J and default re@uire 9ile.-oin%9ile.dirname%AA97D1AA(J HbootH( onfiguration

2ail"::7nitializer.run do M onfigM ? >etting" in onfig/environment"/P ta#e pre eden e t,o"e "pe ified ,ere ? >#ip framewor#" youHre not going to u"e %only wor#" if u"ing vendor/rail"( ? onfig.framewor#" -! ) :a tionAwebA"ervi eJ :a tionAmailer + ? Ldd additional load pat," for your own u"tom dir" onfig.loadApat," N! Y0% ?S2L7D>A2::<T/extra" ( ? 9or e all environment" to u"e t,e "ame logger level ? %by default produ tion u"e" :infoJ t,e ot,er" :debug( ? onfig.logAlevel ! :debug ? O"e t,e databa"e for "e""ion" in"tead of t,e file "y"tem ? % reate t,e "e""ion table wit, Hra#e db:"e""ion": reateH( ? onfig.a tionA ontroller."e""ionA"tore ! :a tiveAre ordA"tore ? O"e >CD in"tead of L tive 2e ordH" " ,ema dumper w,en reating t,e te"t databa"e. ? <,i" i" ne e""ary if your " ,ema anHt be ompletely dumped by t,e " ,ema dumperJ ? li#e if you ,ave on"traint" or databa"e-"pe ifi olumn type" ? onfig.a tiveAre ord." ,emaAformat ! :"@l ? L tivate ob"erver" t,at ",ould alway" be running ? onfig.a tiveAre ord.ob"erver" ! : a ,erJ :garbageA olle tor ? Ba#e L tive 2e ord u"e O<4-ba"e in"tead of lo al time ? onfig.a tiveAre ord.defaultAtimezone ! :ut ? >ee 2ail"::4onfiguration for more option" end ? Ldd new infle tion rule" u"ing t,e following format ? %all t,e"e example" are a tive by default(: ? 7nfle tor.infle tion" do Minfle tM ? infle t.plural /^%ox($/iJ HE1enH

141

? infle t."ingular /^%ox(en/iJ HE1H ? infle t.irregular Hper"onHJ HpeopleH ? infle t.un ountable Yw% fi", ",eep ( ? end ? 7n lude your appli ation re@uire Qu"erAfilter.rbQ onfiguration below

+ arquivo en!ironment.rb contJm uma sJrie uso e certas caracterIsticas

e con"i#ura&es que po em ser mo i"ica as para otimi>ar o e uma aplicao e e apoio se=am carre#a as6 re u>in o o uso

o Rails. Por e0emplo6 se voc@ no preten e enviar e;mails

ou usar Geb services6 po e impe ir que as bibliotecas mem<ria e aumentan o a veloci a e e sua aplicao.

Bo arquivo acima6 = aproveitamos para incluir o nosso arquivo6 que ser carre#a o automaticamente =unto com a aplicao. A#ora6 s< precisamos cri;lo Slembre;se e criar o iret<rio tambJmTA

la"" O"er9ilter def initialize%targetA la""J targetAmet,od( @targetA la"" ! targetA la"" @targetAmet,od ! targetAmet,od end def before% ontroller( filter" ! ontroller."end%@targetAmet,od( @targetA la"".in"tan eAeval do " opedAmet,od" KK wit,A" ope%filter"( S end end def after% ontroller( @targetA la"".in"tan eAeval do " opedAmet,od".pop end end end

urrentA" opedAmet,od" T

A princIpio o arquivo acima po e parecer um pouco esotJrico6 mas J realmente bem simples. AserFilter J a primeira classe que estamos crian o em nossa aplicao que no se encai0a na estrutura pa ro o Rails. Como pensamos em utili>;la como um "iltro o tipo aroun 6 ou se=a6 e0ecuta o antes e epois e uma ao6 precisamos e"inir pelo menos ois mJto osA before e after6 que6 comos os nomes i>em6 ro am antes e epois a ao. Bo caso acima6 precisamos tambJm e um mJto o initiali>e porque vamos passar parLmetros e criao o mJto o

para a classe. /m Rub,6 o mJto o initiali=e J chama a quan o a classe J instancia a atravJs new. Duaisquer parLmetros passa os para new sero passa os tambJm para initiali=e.

Para o nosso "iltro6 precisamos e uas coisasA a classe M qual estaremos aplican o o escopo e qual o escopo a ser aplica o. Como "iltros aroun ro am em conte0tos especiais6 o melhor que po emos "a>er J passar o nome o mJto o que criamos para e"inir o "iltro e invoc;lo no momento em que precisarmos.

14*

Antes e estu armos a classe6 ve=a como "icou o controller epois a aplicao a mesmaA

la"" 4ontext"4ontroller K Lppli ation4ontroller aroundAfilter O"er9ilter.new%4ontextJ :neededA" ope"( def index li"t render :a tion !. Qli"tQ end def li"t @ ontextApage"J @ ontext" ! paginate : ontext"J :perApage !. 5J :order !. QnameQ end def edit if re@ue"t.getU if param"):id+ @ ontext ! 4ontext.find%param"):id+( el"e @ ontext ! 4ontext.new end el"if re@ue"t.po"tU @ ontext ! param"):id+ U 4ontext.update%param"):id+J param"): ontext+( : 4ontext. reate%param"): ontext+( if @ ontext.validU fla",):noti e+ ! Q<,e ontext wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def delete 4ontext.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e ontext wa" "u redire tAto :a tion !. Qli"tQ end prote ted def neededA" ope" @neededA" ope" MM! S :find !. S : ondition" !. )Qu"erAid ! UQJ "e""ion):u"er++ TJ : reate !. S :u"erAid !. "e""ion):u"er+ T T end end

e""fully deletedQ

)e=a que as chama as

iretas a with0scope

esapareceram6 sen o automaticamente aplica as pelo "iltro.

)amos enten er a#ora como a classe "unciona. Dois parLmetros so passa os ao "iltro em sua criaoA a classe que ser mo i"ica a e um mJto o pr<prio controller que simplesA escreve os "iltros a serem aplica os. + mJto o initiali=e o

a classe AserFilter J

def initialize%targetA la""J targetAmet,od( @targetA la"" ! targetA la"" @targetAmet,od ! targetAmet,od end

14'

Apenas #uar amos as variveis passa as na instLncia para serem utili>a as momento. Depois temos o mJto o beforeA

epois. Ba a

e especial atJ o

def before% ontroller( filter" ! ontroller."end%@targetAmet,od( @targetA la"".in"tan eAeval do " opedAmet,od" KK wit,A" ope%filter"( S end end

urrentA" opedAmet,od" T

/sse mJto o J invoca o antes

a ao e recebe como parLmetro o controller

a mesma. A primeira coisa e"inimos antes a mesma. A os escopos

que o mJto o "a> aqui J enviar uma mensa#em para o controller invocan o o mJto o que ob=eto. + mJto o send po e ser usa o em qualquer classe para invocar qualquer mJto o varivel filters aqui receber ento o resulta o necessrios. A se#un a linha usa o mJto o instance0e!al para reali>ar um pouco a invocao6 que so as

como conten o os escopos necessrios Sno caso aqui6 needed0scopesT. Lembre;se que tu o em Rub, J um e"ini&es

e m#ica. /sse mJto o recebe um eriva as e

bloco que6 ao invJs e ser e0ecuta o no conte0to o mJto o atual6 J e0ecuta o no conte0to a instLncia sob o qual "oi invoca o6 no caso aqui6 a pr<pria classe 7ontext. As classes que so -cti!e1ecord::Gase6 ou se=a6 to as as classes que e"inem os nossos mo elos e a os6 possuem vrios

mJto os e variveis relaciona as a escopos. )emos tr@s acimaA with0scope6 scoped0methods e current0scoped0methods. Q trabalhamos com o primeiro e os uma varivel ois se#uintes escrevem respectivamente e instLncia que J arra, com to os os escopos ativos Sfind6 create6 etc.T e um mJto o que

retorna o Pltimo escopo aninha o = que escopos po em ser empilha os. A linha e c< i#o ento "a> al#o interessante. Primeiro6 ela entra em um escopo6 usan o o pr<prio mJto o e obter o controller6 e entro o bloco6 invoca o mJto o o

with0scope6 com os "iltros que acabamos

current0method0scopes para retornar o Pltimo escopo aninha o que "oi a iciona o. /sse J o retorno

bloco que ento J inseri o como mais um item na varivel scoped0methods6 e"etivamente ativan o um escopo na classe. )oc@ po e estar pensan oA mas isso no aplica o escopo uas ve>es` Bo6 pela m#ica os blocosA to lo#o o bloco e with0scope retorne6 o "iltro aplica o J removi o6 se#ui o pela a io o retorno. Aqui vai uma coinci @nciaA epois e ter elabora o a verso acima o c< i#o6 lembrei que e0istia um plu#in que "a>ia =ustamente isso6 e uma maneira bem mais avana a. )oc@ po e encontrar o plu#in e uma a tJcnica que usamos nesse ponto no en ereo se#uinteA escrio muito mais elabora a e completa

http://habtm.com/articles/;"">/";/;;/nested'with0scope. ?nclusive6 a linha acima J uma a aptao e uma linha o plu#in6 que e0ecuta e maneira mais completa o que eu estava "a>en o antes.

144

7inalmente6 o mJto o after remove o escopo cria o no mJto o before6 removen o;o scoped0methods6 se#uin o e0atamente o c< i#o interno o Rails. + resulta o J que6 aplicao o "iltro6 to as as chama as ao controller esto ebai0o os escopos que precisamos.

o arra, e

urante o tempo

-e voc@ acessar a aplicao a#ora6 com usurio i"erentes6 ver que o controller que manipula os conte0tos J capa> e "iltrar per"eitamente os re#istros e acor o com o usurio autentica o no momento6 sem qualquer inter"er@ncia no c< i#o o mesmo. /m nossa aplicao6 queremos que esse "iltro se=a aplica o a to os os controllers. Po erIamos ento mover suas chama as para nosso controller primrio6 que "icaria assimA

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :aut,enti ate "#ipAbeforeAfilter :aut,enti ateAadmini"trationJ :only !. ):a aroundAfilter aroundAfilter aroundAfilter aroundAfilter O"er9ilter.new%4ontextJ :neededA" ope"( O"er9ilter.new%=ro-e tJ :neededA" ope"( O"er9ilter.new%L tionJ :neededA" ope"( O"er9ilter.new%2e"our eJ :neededA" ope"( e""Adenied+

,elperAmet,od :"e""ionAu"er def a e""Adenied render :template !. Q",ared/a end prote ted def "e""ionAu"er @"e""ionAu"er MM! O"er.find%:fir"tJ : ondition" !. )Hid ! UHJ "e""ion):u"er++( end def aut,enti ate unle"" "e""ion):u"er+ "e""ion):returnAto+ ! re@ue"t.re@ue"tAuri redire tAto : ontroller !. QloginQJ :a tion !. QloginQ return fal"e end return true end def aut,enti ateAadmini"tration unle"" "e""ionAu"er [[ "e""ionAu"er.adminU redire tAto :a tion !. Qa e""AdeniedQ return fal"e end return true end def neededA" ope" @neededA" ope" MM! S :find !. S : ondition" !. )Qu"erAid ! UQJ "e""ion):u"er++ TJ : reate !. S :u"erAid !. "e""ion):u"er+ T T end end e""AdeniedQ

Depois6 removemos o c< i#o e nosso controller e conte0tos6 que voltaria aA


145

la"" 4ontext"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @ ontextApage"J @ ontext" ! paginate : ontext"J :perApage !. 5J :order !. QnameQ end def edit if re@ue"t.getU if param"):id+ @ ontext ! 4ontext.find%param"):id+( el"e @ ontext ! 4ontext.new end el"if re@ue"t.po"tU @ ontext ! param"):id+ U 4ontext.update%param"):id+J param"): ontext+( : 4ontext. reate%param"): ontext+( if @ ontext.validU fla",):noti e+ ! Q<,e ontext wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def delete 4ontext.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e ontext wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

Como o escopo J aplica o precisam e mo i"ica&es

iretamente nas classes

a os6 percebemos que nossos controllers no as mu anas para usar os mJto os create e

iretas Scom e0ceo6 J claro6

update ao invJs e sa!e6 a o o problema que percebemos com a aplicao e escopos6 que "ica aqui como um e0ercIcio para o leitorT. -e ro armos al#uns e nossos controllers6 teremos al#uns problemas com as nossas con i&es6 por causa o nome ambI#uo e nosso coluna6 que aparece em vrias classes. .ma "orma rpi a e resolver isso J mu ar o c< i#o e nosso "iltro paraA

la"" O"er9ilter def initialize%targetA la""J targetAmet,od( @targetA la"" ! targetA la"" @targetAmet,od ! targetAmet,od end def before% ontroller( filter" ! ontroller."end%@targetAmet,odJ @targetA la""( @targetA la"".in"tan eAeval do " opedAmet,od" KK wit,A" ope%filter"( S urrentA" opedAmet,od" T end end def after% ontroller(

141

@targetA la"".in"tan eAeval do " opedAmet,od".pop end end end

/ o nosso controller base paraA

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :aut,enti ate "#ipAbeforeAfilter :aut,enti ateAadmini"trationJ :only !. ):a aroundAfilter aroundAfilter aroundAfilter aroundAfilter O"er9ilter.new%4ontextJ :neededA" ope"( O"er9ilter.new%=ro-e tJ :neededA" ope"( O"er9ilter.new%L tionJ :neededA" ope"( O"er9ilter.new%2e"our eJ :neededA" ope"( e""Adenied+

,elperAmet,od :"e""ionAu"er def a e""Adenied render :template !. Q",ared/a end prote ted def "e""ionAu"er @"e""ionAu"er MM! O"er.find%:fir"tJ : ondition" !. )Hid ! UHJ "e""ion):u"er++( end def aut,enti ate unle"" "e""ion):u"er+ "e""ion):returnAto+ ! re@ue"t.re@ue"tAuri redire tAto : ontroller !. QloginQJ :a tion !. QloginQ return fal"e end return true end def aut,enti ateAadmini"tration unle"" "e""ionAu"er [[ "e""ionAu"er.adminU redire tAto :a tion !. Qa e""AdeniedQ return fal"e end return true end def neededA" ope"%targetA la""( S :find !. S : ondition" !. )Q?StargetA la"".tableAnameT.u"erAid ! UQJ "e""ion):u"er++ TJ : reate !. S :u"erAid !. "e""ion):u"er+ T T end end e""AdeniedQ

.san o a pr<pria classe passa a como parLmetro6 especi"icamos melhor a con io e "iltro. ?sso resolve a maior parte os nossos problemas e encontramos uma maneira simples e "iltrar os re#istros que precisamos sem ter que espalhar con i&es por to a a nossa aplicao. Como menciona o anteriormente6 escopos eve ser usa os com cui a o6 mas o"erecem solu&es e0tremamente ele#antes para
14!

etermina os problemas.

XML
.ma as coisas que po emos "a>er em Rails J retornar 9(L para consumo e clientes em qualquer "ormato que precisamos. /m uma aplicao como a nossa6 um e0emplo e 9(L que po ermos querer pro u>ir J um

"ee R--.
/u ima#ino que a maioria e n<s este=a "amiliar com esse tipo e tecnolo#ia. Aqueles que no estiverem

po em encontrar mais in"orma&es em http://www.rssficado.com.br/. -eria interessante que os usurios a nossa aplicao "osse capa>es e acessarem um "ee R-- com as

a&es que precisam e0ecutar. Po erIamos ter simplesmente uma lista#em

as a&es ain a no reali>a as

que seria automaticamente atuali>a a caso um novo re#istro "osse inseri o na base e a os. Como mencionamos anteriormente6 o Rails po e pro u>ir no s< saI a 4:(L6 mas qualquer outra que se=a necessria. Bo caso aqui6 vamos pro u>ir saI a 9(L que J automaticamente suporta a pelo mecanismo templates o Rails. Para comear6 vamos #erar um novo controllerA e

ronaldo@minerva:~/tmp/gtd$ " ript/generate ontroller feed exi"t" app/ ontroller"/ exi"t" app/,elper"/ reate app/view"/feed exi"t" te"t/fun tional/ reate app/ ontroller"/feedA ontroller.rb reate te"t/fun tional/feedA ontrollerAte"t.rb reate app/,elper"/feedA,elper.rb

/sse controller ter somente uma ao que retornar o nosso "ee R--A

la"" 9eed4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.find :allJ : ondition" !. )Qdone ! 'Q+J :order !. Q reatedAat de" Q render :layout !. fal"e end end

Ba ao acima6 pe#amos to as as a&es ain a em aberto6 or ena as em

ata

ecrescente

e criao.

Precisamos tambJm ren eri>ar a ao sem la,out = que a vieG associa a #erar tu o o que precisamos. A#ora6 precisamos criar a vieG relaciona a com essa ao. Besse caso6 ao invJs index.rhtml6 usaremos um arquivo chama o index.rxmlA e #erarmos um arquivo

xml.in"tru tW

145

xml.r"" Qver"ionQ !. Q&.'QJ Qxmln":d Q !. Q,ttp://purl.org/d /element"/1.1/Q do xml. ,annel do xml.title xml.lin# xml.pubGate xml.de" ription QGue L tion"Q urlAfor%:onlyApat, !. fal"eJ : ontroller !. Qa tion"Q( 4X7.rf 11&3Adate%@a tion".fir"t. reatedAat( if @a tion".anyU QGue a tion"Q

@a tion".ea , do Ma tionM xml.item do xml.title a tion.de" ription xml.lin# urlAfor%:onlyApat, !. fal"eJ : ontroller !. Qa tion"QJ :a tion !. QeditQJ :id !. a tion.id( xml.pubGate 4X7.rf 11&3Adate%a tion. reatedAat( xml.guid urlAfor%:onlyApat, !. fal"eJ : ontroller !. Qa tion"QJ :a tion !. QeditQJ :id !. a tion.id( end end end end

A varivel xml est automaticamente presente e J uma instLncia

a class HmlGuilder6 que permite uma

aplicao #erar 9(L quase como se estivesse escreven o c< i#o Rub,. Por meio e uma aplicao interessante as proprie a es a lin#ua#em6 a classe HmlGuilder intercepta as eclara&es automticas e elementos 9(L6 que

chama as a mJto os ine0istentes e os trans"orma em po em ser aninha os com o uso e blocos.

A tJcnica usa a J e0atamente a mesma #era a para criar os mJto os automticos que temos nas classes e a os6 no "ormato find0@6 crian o o necessrio no momento em que a primeira invocao J "eita que o esenvolve or possa utili>ar a classe como se to os os atributos anteriormente. + resulta o J o se#uinteA e mo o o arquivo 9(L e0istissem

142

Como voc@ po e ver6 ca a elemento

escrito atravJs

o ob=eto xml /"oi #era o6 no que no passa

e uma

vieG normal utili>an o outro "ormato.


:emos6 porJm6 um problema com o uso esse "ee . -e o intro u>irmos em um leitor R--6 veremos que o

mesmo simplesmente "alha porque6 sem autenticao6 tu o o que o que J retorna o J um re irecionamento para a p#ina e lo#in. Precisamos ento e um maneira alternativa e autenticar o nosso "ee .

AUTENTICAO HTTP
.ma "orma e "a>er isso J usar a autenticao = usa a por nave#a ores6 cu=os tipos principais so 3asic6 os nave#a ores em e0ist@ncia. A primeira J a Di#est e B:L(. As tr@s so suporta as pela maior parte proprietria6 sen o uma variao

"orma mais simples6 mas mais "acilmente interceptvel. A terceira J bem se#ura6 mas comple0a e o pa ro Ferberos usa a pela (icroso"t. /mbora suporta a por outros os a#re#a ores no a nave#a ores6 no J o que queremos implementar no momento = que a maioria
15$

suporta. 7icamos ento com a 3asic6 cu=o uso J relativamente simples e que J suporta a pelos principais leitores e R--. Para "a>er po ermos usar essa autenticao6 precisamos mu ar o nosso "iltro e lo#in. A autenticao 3asic "unciona basicamente com o uso envia os pelo nave#a or. 3asta recuperamos esses e um obscurecimento simples o lo#in e senha

a os e conse#uiremos o que precisamos para

i enti"icar o usurio. )e=amos como o nosso controller "icariaA

la"" 9eed4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.find :allJ : ondition" !. )Qdone ! 'Q+J :order !. Q reatedAat de" Q render :layout !. fal"e end prote ted def aut,enti ate loginJ pa""word ! getAba"i Adata u"er ! O"er.findAbyAloginAandApa""word%loginJ pa""word( if u"er "e""ion):u"er+ ! u"er.id return true el"e ,eader")Q>tatu"Q+ ! QOnaut,orizedQ ,eader")Q000-Lut,enti ateQ+ ! Q/a"i realm!EQX<GEQQ render :text !. Q9ailed to aut,enti ate t,e provided login and pa""wordQJ :"tatu" !. Q$'1 Onaut,orizedQ return fal"e end end def getAba"i Adata loginJ pa""word ! QQJ QQ if re@ue"t.env.,a"A#eyU%Q_-;<<=ALO<;:27`L<7:8Q( data ! re@ue"t.env)Q_-;<<=ALO<;:27`L<7:8Q+.toA"."plit el"if re@ue"t.env.,a"A#eyU%Q;<<=ALO<;:27`L<7:8Q( data ! re@ue"t.env)Q;<<=ALO<;:27`L<7:8Q+.toA"."plit end if data and data)'+ !! Q/a"i Q loginJ pa""word ! /a"e*$.de ode*$%data)1+(."plit%Q:Q()'..1+ end return )loginJ pa""word+ end end

+ que "i>emos acima "oi mu ar o "iltro que "a> a autenticao. De autenticao basea a em uma p#ina

lo#in6 temos a#ora autenticao 3asic. Como nosso controller her a to os os seus mJto os
e somente criar um outro "iltro porque nossos escopos iniciali>a a nesse "iltro. -e a icionssemos outros6 os "iltros epen em e uma varivel

o controller

base6 para trocarmos a implementao e um mJto o6 basta re e"inI;lo. Precisamos "a>er isso aqui ao invJs e sesso que J e escopo "alhariam por estarem no controller

base e ro arem antes e qualquer "iltro e"ini o em outro classe. + novo mJto o authenticate J bem simples. /le veri"ica se os a os e lo#in recebi os correspon em a um

151

usurio vli o. -e sim6 os retorna os6 posterior.

a os so salvos em sesso para uso em nossos "iltros anteriores6 o valor

ver a eiro J retorna o. Caso contrrio6 cabealhos in ican o que o usurio no "oi autori>a o so e acor o com a especi"icao6 =unto com o valor "alse para bloquear qualquer processamento

+ mJto o get0basic0data6 por sua ve>6 tenta obter testa os em or em. Depois

a os

e autenticao

as variveis

e ambiente

#era as pelo servi or em resposta ao nave#a or. Como eses

a os po em estar em

ois locais6 elas so a os presentes so

isso6 se a autenticao "or realmente 3asic6 os

eco i"ica os o "ormato 3ase146 usa o pelo nave#a or e retorna os. + resulta o J o se#uinteA

-e o usurio recusa a autenticao6 vemos al#o assim Sno ?nternet /0plorer po e "icar um pouco e acor o com as con"i#ura&es o mesmo6 mas o resulta o "inal J o mesmoTA

i"erente

15*

Precisamos a#ora somente e uma pequena alterao em nosso controller para "inali>;loA

la"" 9eed4ontroller K Lppli ation4ontroller "#ipAbeforeAfilter :aut,enti ate beforeAfilter :aut,enti ateAba"i def index @a tion" ! L tion.find :allJ : ondition" !. )Qdone ! 'Q+J :order !. Q reatedAat de" Q ,eader")Q4a ,e-4ontrolQ+ ! Qno- a ,eQ ,eader")Q4ontent-<ypeQ+ ! Qappli ation/xmlNr""Q render :layout !. fal"e end prote ted def aut,enti ateAba"i loginJ pa""word ! getAba"i Adata u"er ! O"er.findAbyAloginAandApa""word%loginJ pa""word( if u"er "e""ion):u"er+ ! u"er.id return true el"e ,eader")Q>tatu"Q+ ! QOnaut,orizedQ ,eader")Q000-Lut,enti ateQ+ ! Q/a"i realm!EQX<GEQQ render :text !. Q9ailed to aut,enti ate t,e provided login and pa""wordQJ :"tatu" !. Q$'1 Onaut,orizedQ return fal"e end end def getAba"i Adata loginJ pa""word ! QQJ QQ if re@ue"t.env.,a"A#eyU%Q_-;<<=ALO<;:27`L<7:8Q(

15'

data ! re@ue"t.env)Q_-;<<=ALO<;:27`L<7:8Q+.toA"."plit el"if re@ue"t.env.,a"A#eyU%Q;<<=ALO<;:27`L<7:8Q( data ! re@ue"t.env)Q;<<=ALO<;:27`L<7:8Q+.toA"."plit end if data and data)'+ !! Q/a"i Q loginJ pa""word ! /a"e*$.de ode*$%data)1+(."plit%Q:Q()'..1+ end return )loginJ pa""word+ end end

A primeira instruo J para que o nave#a or no use o seu cache interno e a se#un a in ica o tipo e a os que eve ser retorna o quan o usan o R--. A#ora6 po emos ver como o "ee "icaria em um aplicao R-- pr<priaA

Bo so muitas in"orma&es6 mas voc@ = tem uma i Jia

o que J possIvel "a>er com o Rails em termos

#erao e 9(L Sse=a qual "or o "ormato necessrioT e autenticao avana a.

154

Continuan o nosso apren i>a o6 vamos passar a outra parte o Rails.

ENVIANDO E-MAILS
+ Rails possui to a uma parte6 chama a e Action(ailer6 responsvel pelo envio e recebimento e e;mails. Para "ins esse tutorial6 vamos somente usar a parte e envio. -uponhamos que queremos enviar um e;mail para usurio recJm;cria os6 in"orman o;lhes o acesso que o e;mail o

eles a#ora tem ao sistema. Po emos "a>er isso "acilmente. Primeiramente6 J claro6 precisamos usurio6 que no temos em nosso mo elo. Po emos a icionar isso "acilmente com uma mi#raoA

ronaldo@minerva:~/tmp/gtd$ " ript/generate migration addAemailAtoAu"er exi"t" db/migrate reate db/migrate/'1'AaddAemailAtoAu"er.rb

/ itan o a mi#rao6 temosA

la"" Ldd1mail<oO"er K L tive2e ord::Bigration def "elf.up addA olumn :u"er"J :emailJ :"tring end def "elf.down removeA olumn :u"er"J :email end end

Po emos a icionar vali ao a esse campos em nosso mo eloA

la"" O"er K L tive2e ord::/a"e validate"Apre"en validate"Apre"en validate"Apre"en validate"Apre"en eAof eAof eAof eAof :name :login :pa""word :email

validate"Auni@uene""Aof :login end

A vali ao acima somente veri"ica se o e;mail "oi in"orma o6 mas no se o mesmo J vali o. /0iste um

plu#in especI"ico que permite a vali ao real e e;mails que voc@ po e utili>ar nesse caso.
/ a lista#em e usurioA

K,1.O"er"K/,1. KY if fla",):noti e+ Y.

155

Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew O"erQJ :a tion !. QeditQ Y.K/p. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.8ameK/t,. Kt,.DoginK/t,. Kt,.Ldmini"tratorK/t,. Kt,.1-mailK/t,. Kt,.L tion"K/t,. K/tr. KY @u"er".ea , do Mu"erM Y. Ktr. Ktd.KY! u"er.name Y.K/td. Ktd.KY! u"er.login Y.K/td. Ktd.KY! ye"AorAnoU%u"er.adminU( Y.K/td. Ktd.KY! u"er.email Y.K/td. Ktd. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. u"er Y. or KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. u"er TJ : onfirm !. QLre you "ureUQ Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@u"erApage"( Y.K/p.

7inalmente6 a e ioA

K,1.KY if @u"er.newAre ordU Y.8ewKY el"e Y.1ditingKY end Y. O"erK/,1. KY! errorAme""age"Afor Qu"erQ Y. KY! "tartAformAtag :a tion !. QeditQJ :id !. @u"er Y. Kp. Klabel for!Qu"erAnameQ.8ame:K/label.Kbr. KY! textAfield Qu"erQJ QnameQ Y. K/p. Kp. Klabel for!Qu"erAloginQ.Dogin:K/label.Kbr. KY! textAfield Qu"erQJ QloginQ Y. K/p. Kp. Klabel for!Qu"erApa""wordQ.=a""word:K/label.Kbr. KY! pa""wordAfield Qu"erQJ Qpa""wordQ Y. K/p. Kp. Klabel for!Qu"erAadminQ.Ldmini"trator:K/label.Kbr. KY! "ele t Qu"erQJ QadminQJ ))Q8oQJ fal"e+J )QFe"QJ true++ Y. K/p. Kp. Klabel for!Qu"erAemailQ.1-mail:K/label.Kbr. KY! textAfield Qu"erQJ QemailQ Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#Ato Q4an elQJ :a tion !. Qli"tQY. K/p. KY! endAformAtag Y.

151

A#ora precisamos e uma "orma e enviar um e;mail para novos usurios. Para enviar e;mails6 o Rails utili>a

mailers6 que representam tanto o aspecto


com o se#uinte coman oA

o mo el como

a vieG na estratJ#ia ()C. %eramos um novo

ronaldo@minerva:~/tmp/gtd$ " ript/generate mailer regi"trationAnotifier exi"t" app/model"/ reate app/view"/regi"trationAnotifier exi"t" te"t/unit/ reate te"t/fixture"/regi"trationAnotifier reate app/model"/regi"trationAnotifier.rb reate te"t/unit/regi"trationAnotifierAte"t.rb

Como voc@ po e ver6 esse coman o um arquivo em app/models6 que contJm o se#uinteA

la"" 2egi"tration8otifier K L tionBailer::/a"e end

V nessa classe que criaremos os mJto os que #eram o e;mail a ser envia o6 incluin o os seus

a os. /ssa

classe utili>a uma vieG associa o ao mJto o para #erar o conteP o o e;mail. Comearemos com o mJto oA

la"" 2egi"tration8otifier K L tionBailer::/a"e def regi"trationAnotifi ation%u"erJ "e""ionAu"er( re ipient" Q?Su"er.nameT K?Su"er.emailT.Q from Q?S"e""ionAu"er.nameT K?S"e""ionAu"er.emailT.Q "ub-e t Q2egi"trationQ body Qu"erQ !. u"er end end

+ que esse mJto o "a> J #erar os campos e corpo

o e;mail. +s

a os acima so os bsicos. /m or emA e quem enviouK sub%ect6 o o po e e e0pressivi a e o

recipient6 o en ereo para o qual o e;mail ser envia oK from6 o en ereo isponIvel na mesma atravJs a associao. )amos aqui mais uma mostra

assunto o e;mailK e body6 o corpo a mensa#em6 que ser #era o a partir e uma vieG6 com a varivel user/ Rails6 atravJs o uso e mJto os que e"inem uma lin#ua#em e omInio especI"ica. Consultan o a ocumentao6 voc@ ver que po emos manipular outros cabealhos como cc6 bcc e sent0on6 representan o respectivamente os cabealhos c<pia;carbono6 c<pia;carbono invisIvel e ata e envio. )amos enviar um e;mail simples6 mas na ocumentao voc@ tambJm ver que J possIvel enviar mensa#ens 4:(L e6 inclusive6 mensa#ens com partes mPltiplas6 para uso com ane0os e outros a os. Para #erarmos o corpo acima6 "ican o o a mensa#em6 precisamos e uma vieG com o mesmo nome arquivo como registration0notification.rhtml6 o mJto o que criamos no iret<rio

locali>a o

app/!iews/registration0notifierA
15!

Gear KY! @u"er.name Y.: 0el ome to our X<G appli ation. <o a ,ttp://lo al,o"t:3''/,ome Fou login i" KY! @u"er.login Y.J and your pa""word i" KY! @u"er.pa""word Y.. <,an#" for your intere"t. 2egard"J <,e Ldmini"trator e"" itJ log in to:

Como voc@ po e ver6 um arquivo simples no mesmo estilo as vieGs que = #eramos6 com a Pnica i"erena e ser te0tual. Antes e enviar o nosso e;mail pelo controller6 precisamos e uma mo i"icao na con"i#urao e nossa

aplicaoA in"ormar o servi or pelo qual os e;mails sero envia os. ?sso somente J necessrio se voc@ no tiver um servi or local que respon a em localhost. De qualquer "orma6 como esse po e ser =ustamente o seu caso6 mostramos aqui a mo i"icao necessria6 que acontece no arquivo config/en!iroment.rbA

? /e "ure to re"tart your web "erver w,en you modify t,i" file. ? On omment below to for e 2ail" into produ tion mode w,en ? you donHt ontrol web/app "erver and anHt "et it t,e proper way ? 18Z)H2L7D>A18ZH+ MM! Hprodu tionH ? >pe ifie" gem ver"ion of 2ail" to u"e w,en vendor/rail" i" not pre"ent 2L7D>AX1BAZ12>7:8 ! H1.1.*H ? /oot"trap t,e 2ail" environmentJ framewor#"J and default re@uire 9ile.-oin%9ile.dirname%AA97D1AA(J HbootH( onfiguration

2ail"::7nitializer.run do M onfigM ? >etting" in onfig/environment"/P ta#e pre eden e t,o"e "pe ified ,ere ? >#ip framewor#" youHre not going to u"e %only wor#" if u"ing vendor/rail"( ? onfig.framewor#" -! ) :a tionAwebA"ervi eJ :a tionAmailer + ? Ldd additional load pat," for your own u"tom dir" onfig.loadApat," N! Y0% ?S2L7D>A2::<T/extra" ( ? 9or e all environment" to u"e t,e "ame logger level ? %by default produ tion u"e" :infoJ t,e ot,er" :debug( ? onfig.logAlevel ! :debug ? O"e t,e databa"e for "e""ion" in"tead of t,e file "y"tem ? % reate t,e "e""ion table wit, Hra#e db:"e""ion": reateH( ? onfig.a tionA ontroller."e""ionA"tore ! :a tiveAre ordA"tore ? O"e >CD in"tead of L tive 2e ordH" " ,ema dumper w,en reating t,e te"t databa"e. ? <,i" i" ne e""ary if your " ,ema anHt be ompletely dumped by t,e " ,ema dumperJ ? li#e if you ,ave on"traint" or databa"e-"pe ifi olumn type" ? onfig.a tiveAre ord." ,emaAformat ! :"@l ? L tivate ob"erver" t,at ",ould alway" be running ? onfig.a tiveAre ord.ob"erver" ! : a ,erJ :garbageA olle tor ? Ba#e L tive 2e ord u"e O<4-ba"e in"tead of lo al time ? onfig.a tiveAre ord.defaultAtimezone ! :ut

155

? >ee 2ail"::4onfiguration for more option" end ? ? ? ? ? ? ? ? Ldd new infle tion rule" u"ing t,e following format %all t,e"e example" are a tive by default(: 7nfle tor.infle tion" do Minfle tM infle t.plural /^%ox($/iJ HE1enH infle t."ingular /^%ox(en/iJ HE1H infle t.irregular Hper"onHJ HpeopleH infle t.un ountable Yw% fi", ",eep ( end onfiguration below

? 7n lude your appli ation re@uire Qu"erAfilter.rbQ

L tionBailer::/a"e."erverA"etting" ! S :addre"" !. Qmail.yourdomain. omQJ :domain !. Qyourdomain. omQJ :u"erAname !. Qu"er@yourdomain. omQJ :pa""word !. QPPPPPPQJ :aut,enti ation !. :login T

/ ite para os a os necessrios e reinicie o servi or para recarre#ar a nova con"i#urao. Por "im6 precisamos simplesmente mo i"icar o nosso controller responsvel pelos usurios para o envio mensa#em propriamente itoA a

la"" O"er"4ontroller K Lppli ation4ontroller beforeAfilter :aut,enti ateAadmini"tration def index li"t render :a tion !. Qli"tQ end def li"t @u"erApage"J @u"er" ! paginate :u"er"J :perApage !. 5J :order !. QnameQ end def edit if param"):id+ @u"er ! O"er.find%param"):id+( el"e @u"er ! O"er.new end if re@ue"t.po"tU @u"er.attribute" ! param"):u"er+ "endAemail ! @u"er.newAre ordU if @u"er."ave if "endAemail 2egi"tration8otifier.deliverAregi"trationAnotifi ation%@u"er( end fla",):noti e+ ! Q<,e u"er wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def delete O"er.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e u"er wa" "u

e""fully deletedQ

152

redire tAto :a tion !. Qli"tQ end end

Ap<s salvar um usurio novo6 temos o se#uinte resulta o em nossa cai0a e e;mailA

+bviamente6 s< queremos enviar um e;mail para novos usurios. Por isso6 no c< i#o6 antes re#istro6 veri"icamos se o mesmo J novo. -e J6 epois

e salvarmos o

e o salvarmos com sucesso6 enviamos o e;mail. -e

no6 o e;mail J i#nora o. Bote que voc@ no precisa instanciar qualquer classe. )oc@ precisa apenas a icionar deli!er0 ao mJto o que voc@ #erou e o e;mail ser cria o o envia o automaticamente. Como po emos ver6 a maneira e enviar e;mail no Rails J bem simples.

DEPURANDO APLICAES
.ma coisa que o Rails permite e que no vimos atJ o momento J a problemas. Para comearmos6 usaremos um novo coman o o RailsA epurao e aplica&es atravJs e seu e console. /ssa J uma caracterIstica muito simples6 mas e0tremamente Ptil na i enti"icao rpi a

11$

ronaldo@minerva:~/tmp/gtd$ " ript/brea#pointer 8o onne tion to brea#point "ervi e at druby://lo al,o"t:$&531 %G2b::G2b4onn1rror( <rie" to onne t will be made every & "e ond"...

/sse coman o inicial o

epura or remoto

o Rails6 que espera na porta especI"ica por cone0&es. Com o

coman o inicia o6 po emos intro u>ir um brea8point em nossa aplicao. )amos colocar um em um lu#ar qualquer apenas para emonstraoA

la"" O"er"4ontroller K Lppli ation4ontroller beforeAfilter :aut,enti ateAadmini"tration def index li"t render :a tion !. Qli"tQ end def li"t @u"erApage"J @u"er" ! paginate :u"er"J :perApage !. 5J :order !. QnameQ brea#point end def edit if param"):id+ @u"er ! O"er.find%param"):id+( el"e @u"er ! O"er.new end if re@ue"t.po"tU @u"er.attribute" ! param"):u"er+ "endAemail ! @u"er.newAre ordU if @u"er."ave if "endAemail 2egi"tration8otifier.deliverAregi"trationAnotifi ation%@u"erJ "e""ionAu"er( end fla",):noti e+ ! Q<,e u"er wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def delete O"er.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e u"er wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

)oltan o ao coman o6 veremos o se#uinteA

ronaldo@minerva:~/tmp/gtd$ " ript/brea#pointer 8o onne tion to brea#point "ervi e at druby://lo al,o"t:$&531 %G2b::G2b4onn1rror( <rie" to onne t will be made every & "e ond"... 1xe uting brea# point at ./" ript/../ onfig/../app/ ontroller"/u"er"A ontroller.rb:1& in \li"tH irb%?KO"er"4ontroller:'xbRR35e$ .(:''1:'.

A aplicao a#ora est para a e po e ser acessa a pelo consoleA

111

irb%?KO"er"4ontroller:'xbRR35e$ .(:''1:'. @u"er" !. )?KO"er:'xbRR'31a$ @attribute"!SQnameQ!.QLle""andraQJ QadminQ!.Q'QJ QidQ!.Q1&QJ Qpa""wordQ!.Qte"tQJ QloginQ!.Qale""andraQJ QemailQ!.Qale""andra@refle tive"urfa e. omQT.J ?KO"er:'xbRR'3'8 @attribute"!SQnameQ!.QBar u"QJ QadminQ!.Q'QJ QidQ!.Q&QJ Qpa""wordQ!.Qte"tQJ QloginQ!.Qmar u"QJ QemailQ!.Qmar u"@refle tive"urfa e. omQT.J ?KO"er:'xbRR'&fR$ @attribute"!SQnameQ!.Q2onaldoQJ QadminQ!.Q1QJ QidQ!.Q1QJ Qpa""wordQ!.Qte"tQJ QloginQ!.QronaldoQJ QemailQ!.Qronaldo@refle tive"urfa e. omQT.+ irb%?KO"er"4ontroller:'xbRR35e$ .(:''&:'.

:estan o mais um poucoA

irb%?KO"er"4ontroller:'xbRR35e$ .(:'11:'. in"tan eAvariable" !. )Q@re"pon"eQJ Q@performedAredire tQJ Q@,eader"QJ Q@u"erApage"QJ Q@a tionAnameQJ Q@fla",QJ Q@templateQJ Q@ oo#ie"QJ Q@AAbpAfileQJ Q@urlQJ Q@performedArenderQJ Q@beforeAfilterA ,ainAabortedQJ Q@"e""ionAu"erQJ Q@a""ign"QJ Q@"e""ionQJ Q@param"QJ Q@re@ue"tAoriginQJ Q@variable"AaddedQJ Q@re@ue"tQJ Q@AAbpAlineQJ Q@u"er"Q+ irb%?KO"er"4ontroller:'xbRR35e$ .(:'1&:'. lo alAvariable" !. )QAQ+ irb%?KO"er"4ontroller:'xbRR35e$ .(:'13:'. re@ue"t.re@ue"tAuri !. Q/u"er"/li"tQ irb%?KO"er"4ontroller:'xbRR35e$ .(:'1$:'. !. Qu"er"Q ontrollerAname

:u o o que est

isponIvel no ambiente po e ser acessa o

a linha

e coman o e c< i#o Rub, arbitrrio

po e ser e0ecuta o tambJm. 7inalmente6 para sair6 use o coman o e0it6 que retorna o controle M aplicao. (Pltiplos brea8points po em ser usa os para para as seqRenciais. Besse caso6 e0it mover a e0ecuo para o pr<0imo brea8point. Como po emos ver6 a epurao e aplica&es J to simples em Rails quanto qualquer outra tare"a.

ASSOCIAES POLIMRFICAS
.m tipo e associao que no tivemos oportuni a e e e0plorar atJ o momento so associa&es e associao J mais uma as novi a es que "oram intro u>i as no Rails 1.1 e so polim<r"icas. /sse tipo

responsveis por uma "acili a e muito maior em certos tipos e aplica&es. )amos supor que6 em nossa aplicao6 tivJssemos a necessi a e e saber sobre ca a mo i"icao "eita a

um re#istro6 ou se=a6 au itar ca a operao e persist@ncia ao banco e a os. /ssa J uma necessi a e que eu = encontrei em al#umas aplica&es6 especialmente requisita a pelo usurio. Para arma>enar esses a os6 po erIamos criar um tabela que conteria o ata a operao6 o tipo e

operao6 o usurio que a reali>ou e o ob=eto sobre o qual a mesma "oi reali>a a. Bo caso aqui6 para emonstrar as nossas associa&es6 vamos i#norar um etalhe <bvioA a au itoria a remoo o ob=eto que6 pelo mJto o que vamos empre#ar6 no "uncionaria6 = que o ob=eto est sen o removi o o banco e a os e qualquer associao com o mesmo se tornaria invli a nesse instante. ?#noran o isso6 a primeira coisa precisamos "a>er J criar a tabela que conter nossos re#istros e criao e
11*

atuali>ao. )amos criar o mo elo au itoriasA

a os

iretamente = que no precisamos6 no momento6 e0ibir as

ronaldo@minerva:~/tmp/gtd$ " ript/generate model audit exi"t" app/model"/ exi"t" te"t/unit/ exi"t" te"t/fixture"/ reate app/model"/audit.rb reate te"t/unit/auditAte"t.rb reate te"t/fixture"/audit".yml exi"t" db/migrate reate db/migrate/'11A reateAaudit".rb

Depois e cria o o mo elo6 e itamos a mi#raoA

la"" 4reateLudit" K L tive2e ord::Bigration def "elf.up reateAtable :audit" do MtM t. olumn :operationJ :"tring t. olumn :re ordedAatJ :datetime t. olumn :auditableAidJ :integer t. olumn :auditableAtypeJ :"tring t. olumn :u"erAidJ :"tring end end def "elf.down dropAtable :audit" end end

+ si#ni"ica o as uas colunas auditable0id e auditable0type se tornar claro em um instante. Com o mo elo em mos6 po emos e it;loA

la"" Ludit K L tive2e ord::/a"e belong"Ato :auditableJ :polymorp,i end !. true

/ssa linha J importante. /la in ica a inter"ace polim<r"ica que vamos a otar para nossa aplicao. + nome J arbitrrio mas6 uma ve> escolhi o6 ser usa o na in icao a associa&es. /scolhen o um mo elo qualquer6 po emos "a>er o se#uinte a#oraA

la"" 4ontext K L tive2e ord::/a"e attrAprote ted :u"erAid validate"Apre"en eAof :name validate"Auni@uene""Aof :name validate"Apre"en eAof :u"erAid

11'

,a"Amany :a tion" ,a"Amany :audit"J :a" !. :auditable end

A e"inio a associao a#ora possui um novo parLmetro que in ica a inter"ace polim<r"ica que e"inimos. / a#ora6 po emos usar a associao6 pelo consoleA

ronaldo@minerva:~/tmp/gtd$ " ript/ on"ole Doading development environment. .. ontext ! 4ontext.find%1( !. ?K4ontext:'xbR8''R*$ @attribute"!SQnameQ!.Q@;omeQJ QidQ!.Q1QJ Qu"erAidQ!.Q1QT. .. ontext.audit" !. )+ .. ontext.audit". reate%:operation !. Qin"ertQJ :re ordedAat !. Gate<ime.now( !. ?KLudit:'xbRReaR' @newAre ord!fal"eJ @error"!?KL tive2e ord::1rror":'xbRRe5 5 @ba"e!?KLudit:'xbRReaR' ....J @error"!ST.J @attribute"!SQre ordedAatQ!.?KGate<ime: 1'*'1&65$818&8*56R/$3&''''''''J-1/8J&&661*1.J QauditableAtypeQ!.Q4ontextQJ QidQ!.1J QauditableAidQ!.1J QoperationQ!.Qin"ertQT. .. ontext.audit")'+.auditableAid !. 1 .. ontext.audit")'+.auditableAtype !. Q4ontextQ

+ si#ni"ica o

as colunas se torna claro a#oraA a coluna auditable0id contJm o i enti"ica or

o re#istro

relaciona o M associaoHno caso acima6 o conte0to com o i contJm o nome a classe relaciona aHno caso acima6 Conte0t. )amos testar com outro mo eloA

cu=o valor J 1He a coluna auditable0type/

la"" =ro-e t K L tive2e ord::/a"e validate"Apre"en eAof :name validate"Auni@uene""Aof :name ,a"Amany :a tion" ,a"Amany : ontext"J :t,roug, !. :a tion"J :"ele t !. Qdi"tin t ,a"Amany :audit"J :a" !. :auditable end ontext".PQ

Ain a no console6 po emos "a>erA

.. reloadW 2eloading... !. )LuditJ Lppli ation4ontrollerJ 4ontextJ =ro-e tJ L tionJ 2e"our e+ .. pro-e t ! =ro-e t.find%1(

114

!. ?K=ro-e t:'xbRR8*R&' @attribute"!SQnameQ!.Q/uild a ;ou"eQJ QidQ!.Q1QJ Qde" riptionQ!.QQJ Qu"erAidQ!.Q1QJ Qa tiveQ!.Q1QT. .. pro-e t.audit" !. )+ .. pro-e t.audit". reate%:operation !. Qin"ertQJ :re ordedAat !. Gate<ime.now( !. ?KLudit:'xbRRR*6*' @newAre ord!fal"eJ @error"!?KL tive2e ord::1rror":'xbRR*eb$8 @ba"e!?KLudit:'xbRRR*6*' ....J @error"!ST.J @attribute"!SQre ordedAatQ!.?KGate<ime: &1&'&56'66'R3$5*R/8*$'''''''J-1/8J&&661*1.J QauditableAtypeQ!.Q=ro-e tQJ QidQ!.&J QauditableAidQ!.1J QoperationQ!.Qin"ertQT. .. pro-e t.audit")'+.auditableAid !. 1 .. pro-e t.audit")'+.auditableAtype !. Q=ro-e tQ

Bote o uso e reloadI para recarre#ar os mo elos recJm;mu a os. / ve=a que o re#istro cria o para a nova classe que usamos mu a o tipo a associao automaticamente. Dualquer outra classe que usssemos "aria o mesmo. -elecionan o os a os no (,-DL6 vemos os a os emonstran o isso claramenteA

my"@l. "ele t P from audit"5 N----N-----------N---------------------N--------------N----------------N---------N M id M operation M re ordedAat M auditableAid M auditableAtype M u"erAid M N----N-----------N---------------------N--------------N----------------N---------N M 1 M in"ert M &''*-'6-&$ &3:13:56 M 1 M 4ontext M 8ODD M M & M in"ert M &''*-'6-&$ &3:1$:'$ M 1 M =ro-e t M 8ODD M N----N-----------N---------------------N--------------N----------------N---------N & row" in "et %'.'' "e (

Como po emos ver6 associa&es polim<r"icas tem esse nome porque elas so capa>es rela&es para ob=etos /ssas colunas so usa as pelo Rails para #erar

e representar

i"erentes por meio e colunas especiais que recebem seus valores automaticamente. eclara&es -DL especI"icas6 basea as na classe que est

"a>en o a chama a6 transparentemente para a aplicao. .ma ve> que temos essas associa&es6 po emos "a>er nossa au itoria vamos utili>ar m< ulos para incorporar essa "uncionali a e aos mo elos. e maneira automtica. Para isso6

MDULOS
Para usar m< ulos nesse caso6 vamos criar um arquivo especI"ico no auditing.rbA iret<rio extras6 chama o

module X<G module Luditing def "elf.appendAfeature"%ba"e( ba"e.afterA reate do Mob-e tM ob-e t.audit". reate%:operation !. Qin"ertQJ :re ordedAat !. Gate<ime.now(

115

end ba"e.afterAupdate do Mob-e tM ob-e t.audit". reate%:operation !. QupdateQJ :re ordedAat !. Gate<ime.now( end end end end

+ que esse arquivo "a> J

e"inir um m< ulo que ser incorpora o aos mo elos na aplicao. Para evitar

colis&es e nomes6 criamos o m< ulo entro e outro6 especI"ico para nossa aplicao. + mJto o append0features6 inerente a m< ulos6 J ro a o automaticamente pelo Rub, quan o um m< ulo J a iciona o a uma classe. Bo caso acima6 usamos o mJto o para a icionar ois "iltros Ms classes em questoA um ap<s a criao e um ap<s ca a operao um re#istro e au itoria aos e0istentes. Precisamos a#ora mu ar o arquivo en!iroment.rb/para requerer o arquivoA e salvamento. /sses mJto os simplesmente a icionam mais

? /e "ure to re"tart your web "erver w,en you modify t,i" file. ? On omment below to for e 2ail" into produ tion mode w,en ? you donHt ontrol web/app "erver and anHt "et it t,e proper way ? 18Z)H2L7D>A18ZH+ MM! Hprodu tionH ? >pe ifie" gem ver"ion of 2ail" to u"e w,en vendor/rail" i" not pre"ent 2L7D>AX1BAZ12>7:8 ! H1.1.*H ? /oot"trap t,e 2ail" environmentJ framewor#"J and default re@uire 9ile.-oin%9ile.dirname%AA97D1AA(J HbootH( onfiguration

2ail"::7nitializer.run do M onfigM ? >etting" in onfig/environment"/P ta#e pre eden e t,o"e "pe ified ,ere ? >#ip framewor#" youHre not going to u"e %only wor#" if u"ing vendor/rail"( ? onfig.framewor#" -! ) :a tionAwebA"ervi eJ :a tionAmailer + ? Ldd additional load pat," for your own u"tom dir" onfig.loadApat," N! Y0% ?S2L7D>A2::<T/extra" ( ? 9or e all environment" to u"e t,e "ame logger level ? %by default produ tion u"e" :infoJ t,e ot,er" :debug( ? onfig.logAlevel ! :debug ? O"e t,e databa"e for "e""ion" in"tead of t,e file "y"tem ? % reate t,e "e""ion table wit, Hra#e db:"e""ion": reateH( ? onfig.a tionA ontroller."e""ionA"tore ! :a tiveAre ordA"tore ? O"e >CD in"tead of L tive 2e ordH" " ,ema dumper w,en reating t,e te"t databa"e. ? <,i" i" ne e""ary if your " ,ema anHt be ompletely dumped by t,e " ,ema dumperJ ? li#e if you ,ave on"traint" or databa"e-"pe ifi olumn type" ? onfig.a tiveAre ord." ,emaAformat ! :"@l ? L tivate ob"erver" t,at ",ould alway" be running ? onfig.a tiveAre ord.ob"erver" ! : a ,erJ :garbageA olle tor ? Ba#e L tive 2e ord u"e O<4-ba"e in"tead of lo al time

111

onfig.a tiveAre ord.defaultAtimezone ! :ut

? >ee 2ail"::4onfiguration for more option" end ? ? ? ? ? ? ? ? Ldd new infle tion rule" u"ing t,e following format %all t,e"e example" are a tive by default(: 7nfle tor.infle tion" do Minfle tM infle t.plural /^%ox($/iJ HE1enH infle t."ingular /^%ox(en/iJ HE1H infle t.irregular Hper"onHJ HpeopleH infle t.un ountable Yw% fi", ",eep ( end onfiguration below

? 7n lude your appli ation re@uire Qu"erAfilter.rbQ re@uire Qauditing.rbQ

L tionBailer::/a"e."erverA"etting" ! S :addre"" !. Qmail.yourdomain. omQJ :domain !. Qyourdomain. omQJ :u"erAname !. Qu"er@yourdomain. omQJ :pa""word !. QPPPPPPQJ :aut,enti ation !. :login T

/ por "im6 a icionamos o m< ulo em um e nossos mo elosA

la"" 4ontext K L tive2e ord::/a"e in lude X<G::Luditing attrAprote ted :u"erAid validate"Apre"en eAof :name validate"Auni@uene""Aof :name validate"Apre"en eAof :u"erAid ,a"Amany :a tion" ,a"Amany :audit"J :a" !. :auditable end

A#ora6 para qualquer operao "eita nesse mo elo e a os6 uma trilha e au itoria ser #rava a. Po emos comprovar isso6 salvan o um re#istro e0istente e crian o um novo6 o que resulta6 em nosso banco6 nos se#uintes re#istrosA

my"@l. "ele t P from audit"5 N----N-----------N---------------------N--------------N----------------N---------N M id M operation M re ordedAat M auditableAid M auditableAtype M u"erAid M N----N-----------N---------------------N--------------N----------------N---------N M 1 M in"ert M &''*-'6-&$ &3:13:56 M 1 M 4ontext M 8ODD M M & M in"ert M &''*-'6-&$ &3:1$:'$ M 1 M =ro-e t M 8ODD M M 3 M update M &''*-'6-&$ &3:16:'3 M 1 M 4ontext M 8ODD M M $ M in"ert M &''*-'6-&$ &3:&$:58 M 1& M 4ontext M 8ODD M N----N-----------N---------------------N--------------N----------------N---------N $ row" in "et %'.'' "e (

.ma mo i"icao que po emos "a>er em nosso m< ulo J permitir automaticamente a criao
11!

e uma

associaoA

module X<G module Luditing def "elf.appendAfeature"%ba"e( ba"e.afterA reate do Mob-e tM ob-e t.audit". reate%:operation !. Qin"ertQJ :re ordedAat !. Gate<ime.now( end ba"e.afterAupdate do Mob-e tM ob-e t.audit". reate%:operation !. QupdateQJ :re ordedAat !. Gate<ime.now( end ba"e.,a"Amany :audit"J :a" !. :auditable end end end

?sso permite que eliminemos a mesma chama a e ca a classe em que usarmos o m< ulo. (o i"icar o resto as classes para usar o m< ulo J um e0ercIcio para o leitor. +bviamente6 no c< i#o acima6 "alta uma coisaA re#istrar o usurio responsvel pelas chama as. A princIpio6 po erIamos pensar em simplesmente usar o atributo user0id presente em vrias classe. (as isso po e no ser vli o para uma situaoA o que acontece com classes que no tem esse atributo` Bo caso aplicao6 s< temos uma6 que J o mo elo e a os e nossa o pr<prio usurio e6 nesse caso no po emos utili>ar o

os re#istros a mesma porque no a ver com usurio que est "a>en o a mo i"icao. Bo po emos usar e sessoHque seria talve> o mJto o mais <bivoHpois sess&es no esto acessIveis a

tambJm uma varivel mo elos.

A soluo J usar um estratJ#ia especial. /0iste um local que seria acessIvel a to os os mo elosA uma varivel e classe que to as outras classes po em acessar. Para isto6 vamos mo i"icar o mo elo e a os e usurios6 que J o local mais propIcio para issoA

la"" O"er K L tive2e ord::/a"e attrAa e""or : urrentAu"erAid eAof eAof eAof eAof :name :login :pa""word :email

validate"Apre"en validate"Apre"en validate"Apre"en validate"Apre"en

validate"Auni@uene""Aof :login end

/ssa varivel po e ser acessa a

iretamente na classe e usa a por qualquer mo elo. A#ora6 precisamos


115

atribuir um valor M mesma antes e qualquer uso as classes. Po emos "a>er isso em nosso controller rai>A

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :aut,enti ate beforeAfilter :"etA urrentAu"erAid "#ipAbeforeAfilter :aut,enti ateAadmini"trationJ :only !. ):a aroundAfilter aroundAfilter aroundAfilter aroundAfilter O"er9ilter.new%4ontextJ :neededA" ope"( O"er9ilter.new%=ro-e tJ :neededA" ope"( O"er9ilter.new%L tionJ :neededA" ope"( O"er9ilter.new%2e"our eJ :neededA" ope"( e""Adenied+

,elperAmet,od :"e""ionAu"er def a e""Adenied render :template !. Q",ared/a end prote ted def "etA urrentAu"erAid O"er. urrentAu"erAid ! "e""ion):u"er+ end def "e""ionAu"er @"e""ionAu"er MM! O"er.find%:fir"tJ : ondition" !. )Hid ! UHJ "e""ion):u"er++( end def aut,enti ate unle"" "e""ion):u"er+ "e""ion):returnAto+ ! re@ue"t.re@ue"tAuri redire tAto : ontroller !. QloginQJ :a tion !. QloginQ return fal"e end return true end def aut,enti ateAadmini"tration unle"" "e""ionAu"er [[ "e""ionAu"er.adminU redire tAto :a tion !. Qa e""AdeniedQ return fal"e end return true end def neededA" ope"%targetA la""( S :find !. S : ondition" !. )Q?StargetA la"".tableAnameT.u"erAid ! UQJ "e""ion):u"er++ TJ : reate !. S :u"erAid !. "e""ion):u"er+ T T end end e""AdeniedQ

Com isso "eito6 po emos "a>er a mo i"icao em nosso m< ulo e au itoriaA

module X<G module Luditing def "elf.appendAfeature"%ba"e( ba"e.afterA reate do Mob-e tM ob-e t.audit". reate%:operation !. Qin"ertQJ

112

:re ordedAat !. Gate<ime.nowJ :u"erAid !. O"er. urrentAu"erAid( end ba"e.afterAupdate do Mob-e tM ob-e t.audit". reate%:operation !. QupdateQJ :re ordedAat !. Gate<ime.nowJ :u"erAid !. O"er. urrentAu"erAid( end ba"e.,a"Amany :audit"J :a" !. :auditable end end end

Recarre#an o o nosso servi or e e0ecutan o al#uma operao em nossas classes au ita as6 teremos o se#uinte em nosso banco e a osA

my"@l. "ele t P from audit"5 N----N-----------N---------------------N--------------N----------------N---------N M id M operation M re ordedAat M auditableAid M auditableAtype M u"erAid M N----N-----------N---------------------N--------------N----------------N---------N M 1 M in"ert M &''*-'6-&$ &3:13:56 M 1 M 4ontext M 8ODD M M & M in"ert M &''*-'6-&$ &3:1$:'$ M 1 M =ro-e t M 8ODD M M 3 M update M &''*-'6-&$ &3:16:'3 M 1 M 4ontext M 8ODD M M $ M in"ert M &''*-'6-&$ &3:&$:58 M 1& M 4ontext M 8ODD M M 5 M update M &''*-'6-&$ &3:&*:35 M 1& M 4ontext M 8ODD M M * M update M &''*-'6-&$ &3:$':$& M 1& M 4ontext M 1 M M R M in"ert M &''*-'6-&$ &3:$':5* M 13 M 4ontext M 1 M N----N-----------N---------------------N--------------N----------------N---------N R row" in "et %'.'' "e (

/ssa J outra tJcnica que po emos usar em nossos m< ulos para acessar ob=etos ou valores que precisamos. Deve ser usa a com cui a o6 pois po e #erar c< i#o espa#uete6 mas J uma maneira "cil e interessante trans"erir a os e acor o com a necessi a e. e

AJAX
.ma as #ran es ten @ncias atuais no esenvolvimento e aplica&es Eeb J o que se tornou conheci o e apro0imar as aplica&es Eeb e suas e como Eeb *.$6 que J6 na a mais contrapartes o que uma tentantiva

es8top. Aplica&es "eitas no estilo

a assim chama a Eeb *.$ possuem caracterIsticas

inte#rao e usabili a e muito superiores Ms aplica&es que vinham sen o comumente esto se trans"orman o em uma re"er@ncia para o que eve ou no eve ser "eito na ?nternet. .ma as #ran es marcas esse mo elo e

esenvolvi as e

esenvolvimento so aplica&es que usam novas maneiras e recarre#amento

e e

recuperar

a os no servi or6 basea as em Qava-cript6 para re u>ir a necessi a e os "atores ominantes na e"inio

p#inas to tra icional em aplica&es Eeb. /6 embora essa no se=a a principal caracterIstica aplicao Eeb *.$6 isso J o que se tornou um ?nternet.

e um

o que seria essa nova

1!$

Dentro

essa

e"inio6 a populari>ao

e "erramentas basea as na tJcnica conheci a como A=a0H a qual os "atores pre ominantes na

voc@ com certe>a = ouviu "alar e6 muito provavelmente = utili>ouH"oi um

aceitao essas novas aplica&es. (arca6 mais o que "uncionali a e6 pre ominou inicialmente. Para aqueles que nunca ouviram "alar em A=a06 um ori#inalmente seria uma abreviao as e"ini&es mais comuns J a o pr<prio nome6 que

e As,nchronous Java-cript an

X(L. /mbora se=a pouco mais o que

um uso avana o o que era conheci o como D4:(L6 o aumento <bvio o uso a tJcnica se eve ao "ato e que os nave#a ores mais usa os no merca o estabili>aram suas inter"aces Qava-cript6 4:(L6 9(L e C-- ao ponto e que esenvolver uma aplicao usan o tJcnicas avana as no J mais uma questo e esenvolver vers&es i"erentes a mesma coisa. .m os #ran es motivos a populari>ao o Rails nos Pltimos tempos tem si o o suporte o mesmo a

al#umas

essas bibliotecas que6 embora no se=a as mais avana as e completas6 esto to inte#ra as no

"rameGor8 que usar as mesmas se tornou al#o assumi o e "cil o su"iciente para bene"iciar mesmo o
esenvolve or iniciante. /m nosso tutorial vamos a#ora e0plorar al#umas uma apar@ncia e melhor tempo e resposta. +bviamente6 como qualquer outra tJcnica6 o A=a0 tem suas vanta#ens e i"icul a es6 por e0emplo6 J manter a acessibili a e com limita&es mostrar como resolver essas esvanta#ens. .ma as principais essas inte#ra&es mostran o como o A=a0 po e ser an o;lhes no s< uma usabili a e melhor como

realmente utili>a o para melhorar as nossas aplica&es6

a aplicao6 ou se=a6 no sacri"icar aqueles usurios o tutorial6 nesse ponto no J

e acesso6 se=a quais "orem essas limita&es. + ob=etivo

i"icul a es. Procuramos aqui apenas mostrar rapi amente como a tJcnica isponIvel na ?nternet trabalhan o esses problemas e

po e ser empre#a a. Recomen amos que o leitor que opte por empre#ar qualquer tJcnica relaciona a em sua aplicao procure material que est plenamente apontan o possIveis solu&es. .m os outros #ran es problemas o A=a0 est no uploa e arquivos6 = que as requisi&es so "eitas e se#urana6 impe em

#eralmente via Qava-cript e limita&es que uploa s se=am processa os mais recentes

e tamanho6 veloci a e e principalmente elas como parte

iretamente por trs

as cenas. /0istem solu&es parciais para esses o c< i#o o"icial. /m vers&es

problemas e atJ pouco tempo atrs o Rails suportava uma o Rails6 o suporte "oi retira o

o c< i#o principal e movi o para um plu#in6 uma

emonstrao clara os problemas ain a e0istentes com a tJcnica. Problemas M parte6 a tJcnica J e0tremamente Ptil e suas aplica&es po ero #anhar muito usan o mesmo as implementa&es mais bsicas a mesma. Como menciona o acima6 essa J a nossa proposta aquiA mostrar o que po e ser "eito e permitir que o leitor evolua suas pr<prias solu&es6 apren en o a li ar com os problemas no uso prtico a tJcnica. Depois e to os esses comentrios e ressalvas6 po emos partir para nossa implementao. Para isto6 vamos

1!1

aproveitar a nossa p#ina home que atJ o momento estava convenientemente va>ia. Ba meto olo#ia %:D6 a coisa mais importante J a pr<0ima ao6 ou se=a6 quais a&es voc@ ain a precisa completar. 7a> senti o que a nossa p#ina home se=a um mo o e visuali>ar e trabalhar rapi amente com essas a&es. Para comear6 ento6 vamos simplesmente e0ibir nossas a&es na p#ina principal6 separa as pelo conte0to. )oltan o ao nosso controller6 terIamos o se#uinteA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.find%:allJ : ondition" !. Qdone ! 'QJ :in lude !. ):u"erJ :pro-e tJ : ontext+J :order !. Qa tion".de" riptionQ( end end

Recuperamos as a&es ain a no completa as. Bote que o c< i#o acima assume que voc@ alterou o mo elo e a&es con"orme mostra o abai0o6 crian o uma associao entre usurio e aoA

la"" L tion K L tive2e ord::/a"e attrAprote ted : reatedAatJ : ompletedAat def done!%value( if L tive2e ord::4onne tionLdapter"::4olumn.valueAtoAboolean%value( "elf. ompletedAat ! Gate<ime.now el"e "elf. ompletedAat ! nil end writeAattribute%QdoneQJ value( end belong"Ato : ontext belong"Ato :pro-e t belong"Ato :u"er validate"Apre"en eAof :de" ription validate"Apre"en eAof : ontextAid validate"Apre"en eAof :pro-e tAid ,a"AandAbelong"AtoAmany :re"our e"J :order !. QnameQ end

A#ora que temos nossas a&es6 po emos criar a nossa vieG separan o as a&es por conte0toA

K,1.8ext L tion"K/,1. KY @a tion".groupAby%[: ontext(.ea , do M ontextJ a tion"M Y. Kdiv la""!QgroupQ. K,&.KY! Kul. ontext.name Y.K/,&.

1!*

KY a tion".ea , do Ma tionM Y. Kli.KY! a tion.de" ription Y.K/li. KY end Y. K/ul. K/div. KY end Y.

Ba vieG acima estamos usan o uma tJcnica interessante para separa os as a&es por conte0toA o mJto o group0by. /sse mJto o a#rupa um enumera o qualquer Scomo nossas a&es acimaT em con=untos cu=o critJrio e separao J a mensa#em passa a como parLmetro. /stu ar o mJto o group0by6 no c< i#o implementao inseri o tipo epen e o Rails6 J um bom e0ercIcio para enten er o po er o Rub,. A

e usos to so"istica os e ele#antes

a lin#ua#em que s< o estu o e enten imento

a tJcnica usa a ser su"iciente para avanar ra>oavelmente seu conhecimento a lin#ua#em. + mJto o "oi iretamente no m< ulo que controla enumera&es no Rub,6 passan o a "uncionar para qualquer e"ini a em c< i#o. + parLmetro passa o J tambJm uma a io o o Rub,. /m uma lin#ua#em esttica isso simplesmente no seria e enumerao que venha a ser

Rails6 mo i"ican o a classe -,mbol

possIvel ou seria muito i"Icil e implementar e maneira to simples. )oltan o ao c< i#o acima6 estamos separan o as nossas a&es pelo seu conte0to. + mJto o group0by/ retorna uma tabela hash separa a por conte0to que po e ser usa a em um loop6 como "a>emos acima. /ssa tabela hash possui como chaves o resulta o a mensa#em que passamos como parLmetro Sno caso acima6 o conte0toT e como valor um arra, os ob=etos que "iltramos Sno caso acima6 as a&esT. + resulta o inicial JA

1!'

Como po emos ver6 o mJto o J e0tremamente Ptil6 permitin o uma separao

os

a os

e maneira bem

clara e simpli"ica a. /ssa J uma as vanta#ens e usar uma lin#ua#em inLmica como o Rub,. A#ora6 a icionan o o "ra#mento apresentaoA e C-- abai0o ao nosso arquivo default.css6 melhoramos a nossa

div.group S border: 1px "olid ? margin-bottom: 1'px5 T

div.group ,& S padding: 5px5 margin: 'px5 border-bottom: 1px "olid ? ba #ground- olor: ?ddd5 font-"ize: 11'Y5 T div.group ul S li"t-"tyle: none5 margin: '5 padding: '5 T div.group ul li S

1!4

margin: 8px 15px5

+ resulta o J o se#uinteA

:emos a#ora uma apresentao bsica para trabalharmos. A primeira coisa que queremos J uma maneira e marcar a&es como completa as. -eria interessante para isso e0ibir pelo menos al#umas completa as para termos uma re"er@ncia. Po emos "a>er isso6 mo i"ican o o nosso controllerA as a&es =

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.find%:allJ : ondition" !. Qdone ! 'QJ :in lude !. ):u"erJ :pro-e tJ : ontext+J :order !. Qa tion".de" riptionQ( @ ompletedAa tion" ! L tion.find%:allJ : ondition" !. Qdone ! 1QJ :in lude !. ):u"erJ :pro-e tJ : ontext+J :order !. Qa tion".de" riptionQ(J :limit !. 3 end end

1!5

Po emos tambJm melhorar o nosso c< i#o acima re"atoran o as chama as em um mJto o mais "le0Ivel6 iretamente no mo elo e a os. .m e0emplo isse seriaA

la"" L tion K L tive2e ord::/a"e attrAprote ted : reatedAatJ : ompletedAat def done!%value( if L tive2e ord::4onne tionLdapter"::4olumn.valueAtoAboolean%value( "elf. ompletedAat ! Gate<ime.now el"e "elf. ompletedAat ! nil end writeAattribute%QdoneQJ value( end belong"Ato : ontext belong"Ato :pro-e t belong"Ato :u"er validate"Apre"en eAof :de" ription validate"Apre"en eAof : ontextAid validate"Apre"en eAof :pro-e tAid ,a"AandAbelong"AtoAmany :re"our e"J :order !. QnameQ def "elf.findAbyA"tatu"%doneJ limit ! nil( find :allJ : ondition" !. )Qdone ! UQJ done U 1 : '+J :in lude !. ):u"erJ :pro-e tJ : ontext+J :order !. Qa tion".de" riptionQJ :limit !. limit end end

)oltan o ao nosso controller6 isso ariaA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end end

Depois6 mo i"ican o nossa vieG6 temosA

K,1.8ext L tion"K/,1. KY @a tion".groupAby%[: ontext(.ea , do M ontextJ a tion"M Y. Kdiv la""!QgroupQ. K,&.KY! ontext.name Y.K/,&.

Kul. KY a tion".ea , do Ma tionM Y. Kli.KY! a tion.de" ription Y.K/li.

1!1

KY end Y. K/ul. K/div. KY end Y. Kdiv la""!QgroupQ.

K,&.4ompleted L tion"K/,&. Kul. KY @ ompletedAa tion".ea , do Ma tionM Y. Kli.KY! a tion.de" ription Y.K/li. KY end Y. K/ul. K/div.

+ resulta o "inal J o se#uinteA

A#ora6 po emos intro u>ir al#uma "orma e marcar se a ao est completa a ou noA

1!!

K,1.8ext L tion"K/,1. KY @a tion".groupAby%[: ontext(.ea , do M ontextJ a tion"M Y. Kdiv la""!QgroupQ id!Q ontextAKY! ontext.id Y.Q. K,&.KY! ontext.name Y.K/,&.

Kul. KY a tion".ea , do Ma tionM Y. Kli id!Q ontextAa tionAKY! a tion.id Y.Q. KY! ,e #AboxAtag Q ompleted)?Sa tion.idT+QJ a tion.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. a tion T(TQ Y. KY! a tion.de" ription Y. K/li. KY end Y. K/ul. K/div. KY end Y. Kdiv la""!QgroupQ.

K,&.4ompleted L tion"K/,&. Kul id!Q ompletedAa tion"Q. KY @ ompletedAa tion".ea , do Ma tionM Y. Kli.KY! a tion.de" ription Y.K/li. KY end Y. K/ul. K/div.

+ si#ni"ica o e to os esses i s con"eri os a elementos "icar aparente em breve. Por hora6 o importante J a chama a remota que vamos "a>er. Repare o "ra#mento e c< i#o que intro u>imosA

KY! ,e #AboxAtag Q ompleted)?Sa tion.idT+QJ a tion.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. Qmar#QJ :id !. a tion(TQ

Y.

/sse "ra#mento eclara um elemento e "ormulrio o tipo chec8bo06 chama a Protot,pe. Antes

esmarca o e com um evento onclic8 e uma biblioteca

e"ini o para uma ao em Qava-cript. Aqui entra o A=a0 inte#ra o ao Rails atravJs biblioteca M nossa aplicao. Por pa ro6 no momento em que o esqueleto biblioteca Sentre outrasT "oi coloca a no iret<rio.

e po ermos "a>er e0ecutar o c< i#o acima6 precisamos incorporar essa a aplicao "oi #era o6 essas iret<rio public/%a!ascripts6 como voc@ po e ver visuali>an o o

+ que precisamos J somente invoc;las6 o que conse#uimos com uma pequena mu ana em nosso la,out baseA

K,tml. K,ead. Ktitle.X<GK/title. KY! "tyle",eetAlin#Atag QdefaultQ Y. KY! "tyle",eetAlin#Atag Q" affoldQ Y. KY! -ava" riptAin ludeAtag :default" Y. K/,ead.

1!5

Kbody. K,1 id!Q,eaderQ.X<GK/,1. KY if "e""ionAu"er Y. Kp id!Qlogin-informationQ. Fou are logged in a" K"trong.KY! "e""ionAu"er.name Y.K/"trong.. KY! lin#Ato QDog outQJ : ontroller !. QloginQJ :a tion !. QlogoutQ Y.. K/p. KY end Y. Kul id!QmenuQ. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 4ontext"QJ : ontroller !. Q ontext"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 =ro-e t"QJ : ontroller !. Qpro-e t"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 L tion"QJ : ontroller !. Qa tion"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 2e"our e"QJ : ontroller !. Qre"our e"QJ :a tion !. Qli"tQ Y.K/li. KY if "e""ionAu"er [[ "e""ionAu"er.adminU Y. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 O"er"QJ : ontroller !. Qu"er"QJ :a tion !. Qli"tQ Y.K/li. KY end Y. K/ul. Kdiv id!Q ontent"Q.KY! yield Y.K/div. K/body. K/,tml.

+ resulta o essa chama a6 que po e ser visto visuali>an o;se a c< i#o "onte a p#ina #era a6 J a icionar uma sJrie e bibliotecas Qava-cript M p#ina. -omente "aa a invocao acima se realmente precisar = que elas representam quase *$$F3 e Qava-cript que teriam que ser bai0a os e interpreta os pelo nave#a or. +bviamente6 se o seu servi or estiver con"i#ura o apropria amente6 os arquivos somente ser bai0a os uma Pnica ve>6 sem causar mais o que uma emora na car#a inicial a p#ina. (esmo assim6 J interessante ter um certo cui a o em usar as bibliotecasHe quaisquer outras que "orem necessriasHpara no #erar p#inas que emoram emais a ser carre#a as e cu=a usabili a e J potenciamente re u>i a. A veloci a e e interpretao e Qava-cript varia Assim6 se "or possIvel6 ao invJs e nave#a or para nave#a or e po e ser realmente lenta e uma ve>6 melhor. e acor o com a

em al#uns6 mesmo entre os mais usa os. Por isso6 quanto menos Qava-cript carre#a o necessi a e e no as carre#ue em p#inas on e no "orem necessrias. A nossa p#ina a#ora est assimA

e chamar o c< i#o acima6 intro u>a ca a biblioteca

1!2

-e voc@ clicar em um

os chec8bo0es acima ver que na a aconteceHe0ternamente. -e voc@ consultar o

lo# a aplicao ver que uma ao est sen o chama a por trs as cenasHe obviamente "alhan o porque
no a e"inimos ain a. )oc@ po e tambJm visuali>ar o c< i#o a p#ina para ver o c< i#o que a chama a ao mJto o remote0function #erou. + que essa "uno "a>6 basicamente6 J invocar uma ao que passamos como parLmetro. /la no retorna valor a menos que implementemos a aoA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( end

15$

end

A ao continua no retornan o coisa al#uma6 mas a#ora6 se voc@ clicar em uma

as a&es e recarre#ar a

p#ina6 ver que ela espareceu o seu conte0to e a#ora est na lista e a&es completa as. + ob=etivo a#ora J "a>er a transio a ao visualmente e uma lista para a outra. )amos comear comear "a>en o a ao esaparecer. Para isto6 vamos usar pela primeira ve> um novi a e no Rails 1.1 que so os SRails Qava-criptT6

templates

RQ-

vieGs

escreven o

coman os

Qava-cript.

/ssas

vieGs6

no

surpreen entemente6 "uncionam e maneira similar Ms que escrevem elementos 9(L. Para usar uma vieG conten o um template RQ-6 vamos criar o arquivo mar3.r%s/no iret<rio app/!iews/homeA a vieG a ao mar86 chama o

page.remove Q ontextAa tionA?S@a tion.idTQ

Como voc@ po e ver6 o template J bem pareci o com o que usamos anteriormente para #erar 9(L. A i"erena J que esse #era coman os Qava-cript que so evolvi os para a aplicao e interpreta os assim que so retorna os. Bo caso acima6 um coman o J #era o para remover o elemento especi"ica o pela i passa o ao mJto o remo!e o ob=eto page6 que J automaticamente e"ini o para esse tipo e templates. -e voc@ e0ecutar a ao6 ver que o elemento a#ora aparecer em nossa lista somente a lista simplesmente criar um novo elemento na lista com a realmente JHmas tem a vanta#em esaparece escrio o seu conte0to. Precisamos "a>@;lo a#ora e "a>er issoA primeiro6 po emos a aoK e6 se#un o6 po emos ren eri>ar

e a&es completa as. /0istem

uas maneiras

e a&es completa as novamente. + se#un o mJto o po e parecer mais custosoHe e permitir6 entre outras coisas6 mantermos a nossa apresentao

consistente6 como veremos lo#o abai0o. )amos i>er que6 eventualmente6 queiramos e0ibir mais o que somente a escrio a ao em nossas

listas. -e #eramos simplesmente as nossas listas em ca a lu#ar que precisamos6 veremos que to a ve> que "i>ermos uma mu ana em nossa apresentao6 teremos que mo i"icar to os locais que e0ibem a lista. + que po emos "a>er J usar partials para resolver esse problema. )amos mu ar a nossa vieG principal paraA

K,1.8ext L tion"K/,1. KY @a tion".groupAby%[: ontext(.ea , do M ontextJ a tion"M Y. Kdiv la""!QgroupQ id!Q ontextAKY! ontext.id Y.Q. K,&.KY! ontext.name Y.K/,&.

Kul. KY a tion".ea , do Ma tionM Y. Kli id!Q ontextAa tionAKY! a tion.id Y.Q. KY! ,e #AboxAtag Q ompleted)?Sa tion.idT+QJ a tion.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. a tion T(TQ Y. KY! a tion.de" ription Y.

151

K/li. KY end Y. K/ul. K/div. KY end Y. Kdiv la""!QgroupQ.

K,&.4ompleted L tion"K/,&. KY! render :partial !. Q ompletedAa tion"QJ :ob-e t !. @ ompletedAa tion" Y. K/div.

Precisamos a#ora o partial6 cu=o arquivo ser 0completed0actions.rhtmlA

Kul id!Q ompletedAa tion"Q. KY @ ompletedAa tion".ea , do Ma tionM Y. Kli.KY! a tion.de" ription Y.K/li. KY end Y. K/ul.

+ resulta o visual J o mesmo6 mas h uma #ran e vanta#em. Po emos a#ora atuali>ar a nossa lista inLmicamente. Primeiro6 mu amos a ao mar8 em nosso controllerA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end end

/6 epois isso6 nosso template RQ-A

page.remove Q ontextAa tionA?S@a tion.idTQ page.repla e Q ompletedAa tion"QJ :partial !. Q ompletedAa tion"QJ :ob-e t !. @ ompletedAa tion"

A se#un a linha acima ren eri>a o partial que criamos S= po emos ver aqui os bene"Icios a ren eri>ao. + resulta o6 ap<s clicar em nossa primeira ao mostra a na tela anterior JA

essa separao

ao po ermos reusar o c< i#oT e substitui o elemento 4:(L in"orma o no primeiro parLmetro pelo resulta o

15*

Como po emos ver6 o resulta o

a ao6 embora acesse o servi or e "uncione

entro

o mo elo normal

Rails6 em nenhum momento recarre#a a p#ina. :emos uma situao bem mais prtica para o usurio. Pela aplicao a mesma tJcnica po erIamos criar uma ao reversa unmar8 e remover um elemento a lista e completa as6 retornan o;o ao seu conte0to. .m probleminha que temos em nosso c< i#o J o que acontece quan o remover a Pltima ao conte0to6 ei0an o somente o tItulo o conte0to visIvel na p#ina. + resulta o J visualmente esa#ra vel como po emos ver abai0oA e um

15'

Po emos resolver isso com pequenas mo i"ica&es. Primeiro6 em nosso controllerA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end end

Depois6 em nosso template RQ-A

page.remove Q ontextAa tionA?S@a tion.idTQ

154

page.repla e Q ompletedAa tion"QJ :partial !. Q ompletedAa tion"QJ :ob-e t !. @ ompletedAa tion" if @removeA ontext page.remove Q ontextA?S@a tion. ontext.idTQ end

/stamos utili>an o mJto os novos o ActiveRecor em nossos e0emplos. Caso voc@ no tenha "amiliari a e com os mesmos Se0emplos acima so update0attribute e countT6 consulte a in"orma&es mais etalha as. A mu ana resolve nosso problema como voc@ po er ver testan o mais uma ve> a remoo a Pltima ao e um conte0to. .ma outra coisa que J muito utili>a a em aplica&es A=a0 so in ica&es visuais acontecen o. A primeira "orma e "a>er isso J atravJs e uma in icao e que uma ao est ocumentao para

e que a ao remota comeou e

terminouK a se#un a J in icar o resulta o a ao remota. )amos e0perimentar com ambas. Para a primeira precisamos mo i"ique o seu la,out bsicoA e uma ima#em e in icao. /scolha uma ima#em anima a qualquer e

K,tml. K,ead. Ktitle.X<GK/title. KY! "tyle",eetAlin#Atag QdefaultQ Y. KY! "tyle",eetAlin#Atag Q" affoldQ Y. KY! -ava" riptAin ludeAtag :default" Y. K/,ead. Kbody. K,1 id!Q,eaderQ.X<GK/,1. KY if "e""ionAu"er Y. Kp id!Qlogin-informationQ. Fou are logged in a" K"trong.KY! "e""ionAu"er.name Y.K/"trong.. KY! lin#Ato QDog outQJ : ontroller !. QloginQJ :a tion !. QlogoutQ Y.. K/p. KY end Y. KY! imageAtag%Qindi ator.gifQJ :id !. Qindi atorQJ :"tyle !. Qfloat: rig,t5 margin: 5px5 di"play: noneQ( Y. Kul id!QmenuQ. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 4ontext"QJ : ontroller !. Q ontext"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 =ro-e t"QJ : ontroller !. Qpro-e t"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 L tion"QJ : ontroller !. Qa tion"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 2e"our e"QJ : ontroller !. Qre"our e"QJ :a tion !. Qli"tQ Y.K/li. KY if "e""ionAu"er [[ "e""ionAu"er.adminU Y. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 O"er"QJ : ontroller !. Qu"er"QJ :a tion !. Qli"tQ Y.K/li. KY end Y. K/ul. Kdiv id!Q ontent"Q.KY! yield Y.K/div.

155

K/body. K/,tml.

/stamos usan o uma ima#em chama a/ indicator.gif4 que est no ima#em e a escon emos temporariamente.

iret<rio publicZima#es6 que J a

locali>ao pa ro #era a pelo mJto o image0tag. .san o um pouco e estilo C--6 a=ustamos a posio a

A#ora6 mo i"icamos a nossa vieG6 no ponto em que a ao remota J chama aA

K,1.8ext L tion"K/,1. KY @a tion".groupAby%[: ontext(.ea , do M ontextJ a tion"M Y. Kdiv la""!QgroupQ id!Q ontextAKY! ontext.id Y.Q. K,&.KY! ontext.name Y.K/,&.

Kul. KY a tion".ea , do Ma tionM Y. Kli id!Q ontextAa tionAKY! a tion.id Y.Q. KY! ,e #AboxAtag Q ompleted)?Sa tion.idT+QJ a tion.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. a tion TJ :before !. Y%1lement.",ow%Qindi atorQ((J : omplete !. Y%1lement.,ide%Qindi atorQ(((TQ Y. KY! a tion.de" ription Y. K/li. KY end Y. K/ul. K/div. KY end Y. Kdiv la""!QgroupQ.

K,&.4ompleted L tion"K/,&. KY! render :partial !. Q ompletedAa tion"QJ :ob-e t !. @ ompletedAa tion" Y. K/div.

+ mJto o que #era a chama a remota aceita parLmetros a icionais que nos permitem manipular a chama a. Bo caso aqui6 estamos utili>an o e0ecuta a e0atamente antes ois elesA be"ore6 que recebe uma "uno Qava-cript que J a chama a remotaK e complete6 que recebe outra "uno Qava-cript que J uplas ou simples. Ba

e0ecuta a epois que a requisio termina6 tenha ela suce i o ou no. /stamos usan o uma "orma especial e strin#s no Rails6 usan o +JK4 para evitar ter que "icar escapan o aspas6 se=am "un&es6 usamos chama as e classe Qava-cript e0ibir e escon er o in ica or e ao. -e voc@ e0ecutar a chama a a#ora6 ver provavelmente que o in ica or nem pisca. ?sso acontece porque a chama a local J rpi a emais. Para testar a chama a melhor6 voc@ po e colocar o se#uinte c< i#o na aoA e"ini a na biblioteca Protot,pe para6 respectivamente6

la"" ;ome4ontroller K Lppli ation4ontroller

151

def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' "leep%&( end end

+ resulta o J um bom in ica or avisar o usurio mostra o abai0oA

e ao que6 quan o a re e estiver mais lenta6 servir per"eitamente para

e que sua requisio est sen o processa o6 que al#uma coisa est acontecen o6 como

.m outro tipo e in ica or visual J e0ibir al#uma marcao na pr<pria p#ina in ican o o elemento que "oi mo i"ica o. Bo caso e uma ao completa a6 por e0emplo6 po emos ilumin;la na p#ina usan o um e"eito
15!

e p#ina e"ini o na biblioteca script.aculo.us6 que tambJm vem com o Rails. Precisamos mu ar o nosso partial para associar um i a nossa ao. -em isso6 no seremos capa>es e usar o ob=eto 4:(L no Qava-cript e nosso template. (u an o o nosso partial6 temosA

Kul id!Q ompletedAa tion"Q. KY @ ompletedAa tion".ea , do Ma tionM Y. Kli id!Q ontextAa tionAKY! a tion.id Y.Q.KY! a tion.de" ription Y.K/li. KY end Y. K/ul.

/ mu amos o nosso template RQ-A

page.remove Q ontextAa tionA?S@a tion.idTQ page.repla e Q ompletedAa tion"QJ :partial !. Q ompletedAa tion"QJ :ob-e t !. @ ompletedAa tion" page.vi"ualAeffe t :,ig,lig,tJ Q ontextAa tionA?S@a tion.idTQJ :duration !. 3.5 if @removeA ontext page.remove Q ontextA?S@a tion. ontext.idTQ end

+ resulta o JA

155

A in icao acima permite que o usurio tenha mais uma con"irmao que isso6 o que aconteceu.

e que al#o aconteceu6 e6 mais

.ma mu ana rpi a que po emos "a>er a#ora6 para "acilitar o c< i#o "uturo J compactar o nosso partial para se aplicar a qualquer situao em nossa p#ina. A nossa vieG "icariaA

K,1.8ext L tion"K/,1. KY @a tion".groupAby%[: ontext(.ea , do M ontextJ a tion"M Y. Kdiv la""!QgroupQ id!Q ontextAKY! ontext.id Y.Q. K,&.KY! ontext.name Y.K/,&.

KY! render :partial !. Qa tion"QJ :ob-e t !. a tion" Y. K/div. KY end Y. Kdiv la""!QgroupQ.

K,&.4ompleted L tion"K/,&. KY! render :partial !. Qa tion"QJ :ob-e t !. @ ompletedAa tion" Y. K/div.

(u amos tambJm osso partial6 renomea o para 0actions.rhtml6 "icaria assimA

Kul KY if a tion".fir"t.doneU Y.id!Q ompletedAa tion"QKY end Y.. KY a tion".ea , do Ma tionM Y. Kli id!Q ontextAa tionAKY! a tion.id Y.Q. KY unle"" a tion.doneU Y. KY! ,e #AboxAtag Q ompleted)?Sa tion.idT+QJ a tion.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. a tion TJ :before !. Y%1lement.",ow%Qindi atorQ((J : omplete !. Y%1lement.,ide%Qindi atorQ(((TQ Y. KY end Y. KY! a tion.de" ription Y. K/li. KY end Y. K/ul.

/6 por "im6 nosso template RQ-A

page.remove Q ontextAa tionA?S@a tion.idTQ page.repla e Q ompletedAa tion"QJ :partial !. Qa tion"QJ :ob-e t !. @ ompletedAa tion" page.vi"ualAeffe t :,ig,lig,tJ Q ontextAa tionA?S@a tion.idTQJ :duration !. 3.5 if @removeA ontext page.remove Q ontextA?S@a tion. ontext.idTQ end

.ma

as vanta#ens

e usarmos partials6 mesmo que tenhamos que li ar com

i"erenas como J o nosso

caso aqui6 quan o estamos li an o com a&es ain a no e0ecuta as que so e0ibi as a#rupa as e a&es = e0ecuta as6 que so e0ibi as sem #rupo6 J a possibili a e e manter o nosso c< i#o coeso6 sem nos repetir.

152

/sse J um os princIpios o Rub, e o Rails6 conheci o como DRC ou N Donat Repeat Yoursel"OHou se=a6 "aa qualquer coisa uma Pnica ve>K no copie na a. /sse J um princIpio s<li o evitar muita or e cabea na manuteno resultan o os in"ames usos e copiar e colar c< i#o. /sse J tambJm o princIpio por trs para evitar repeti&es trs os "iltros aroun que criamos e o que "i>emos acima6 mu an o um mJto o e mera con i&es e muitas outras instLncias e buscar para o mo elo6 e esenvolvimento que po e e bu#s a aplicao6 principalmente por evitar a proli"erao

e c< i#o6 mesmo que se=a

e busca. V tambJm J o prIncipio por

e c< i#o nesse tutorial. 7inalmente6 os

plu#ins so uma e0presso "orte


e anlise o c< i#o.

e DRC. DRC J al#o que voc@

eve manter como uma atitu e permanente

Assim6 se precisarmos mu ar o nosso partial6 como no e0emplo abai0o6 J que veremos a vanta#em issoA

Kul KY if a tion".fir"t.doneU Y.id!Q ompletedAa tion"QKY end Y.. KY a tion".ea , do Ma tionM Y. Kli id!Q ontextAa tionAKY! a tion.id Y.Q. KY unle"" a tion.doneU Y. KY! ,e #AboxAtag Q ompleted)?Sa tion.idT+QJ a tion.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. a tion TJ :before !. Y%1lement.",ow%Qindi atorQ((J : omplete !. Y%1lement.,ide%Qindi atorQ(((TQ Y. KY end Y. KY! a tion.de" ription Y.Kbr. K"pan. K"trong.=ro-e t:K/"trong. KY! a tion.pro-e t.name Y. KY if a tion.doneU Y. Kbr.K"trong.4ontext:K/"trong. KY! a tion. ontext.name Y. Kbr.K"trong.4ompleted Lt:K/"trong. KY! a tion. ompletedAat."trftime%QYm/Yd/YyQ( Y. KY end Y. K/"pan. K/li. KY end Y. K/ul.

Com a mu ana acima6 e o se#uinte "ra#mento e C-- em nosso arquivo default.cssA

div.group ul li "pan S font-"ize: 85Y5 di"play: blo #5 margin-left: &.&em5 T

Com isso temosA

12$

A#ora que temos as nossas listas6 po emos e0perimentar com mais um pouco e A=a0 e tambJm com al#uns outros aspectos o Rails. Di#amos que queremos a possibili a e e0ecutar entro e or enar as listas acima por priori a e e ao que queremos

e ca a conte0to. Dueremos uma maneira visual

e "a>er isso6 bem rpi a e "cil. Aqui

entra outra implementao A=a0 presente no RailsA listas or enveis por meio e opera&es ra# an

rop.

Bo caso acima6 J bem "cil "a>er isso. 3asta mo i"icar o nosso partial mais uma ve>. Aproveitamos tambJm para resolver o caso e no termos nenhuma ao completa a6 ei0an o somente o #rupo visIvelA

121

KY if a tion".anyU Y. Kul id!QKY if a tion".fir"t.doneU Y. ompletedAa tion"KY el"e Y. ontextAa tion"AKY! a tion".fir"t. ontext.id Y.KY end Y.Q. KY a tion".ea , do Ma tionM Y. Kli id!Q ontextAa tionAKY! a tion.id Y.Q. KY unle"" a tion.doneU Y. KY! ,e #AboxAtag Q ompleted)?Sa tion.idT+QJ a tion.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. a tion TJ :before !. Y%1lement.",ow%Qindi atorQ((J : omplete !. Y%1lement.,ide%Qindi atorQ(((TQ Y. KY end Y. KY! a tion.de" ription Y.Kbr. K"pan. K"trong.=ro-e t:K/"trong. KY! a tion.pro-e t.name Y. KY if a tion.doneU Y. Kbr.K"trong.4ontext:K/"trong. KY! a tion. ontext.name Y. Kbr.K"trong.4ompleted Lt:K/"trong. KY! a tion. ompletedAat."trftime%QYm/Yd/YyQ( Y. KY end Y. K/"pan. K/li. KY end Y. K/ul. KY unle"" a tion".fir"t.doneU Y. KY! "ortableAelement%Q ontextAa tion"A?Sa tion".fir"t. ontext.idTQ( Y. KY end Y. KY el"e Y. Kul id!Q ompletedAa tion"Q.K/ul. KY end Y.

Bo c< i#o acima6 queremos somente que as nossas listas

e a&es no completa as se=am priori>a as6 =

que6 obviamente6 no precisamos nos importar mais com a&es = termina as. Depois e criamos um i para ca a um e nossas listas6 e0ecutamos a chama a ao mJto o

sortable0element. /sse mJto o J responsvel por #erar o c< i#o Qava-cript necessrio para que um elemento 4:(L representan o uma lista possa ser reor envel atravJs e opera&es ra# an

rop.

/0perimente a#ora clicar sobre um item a lista e mov@;lo. Como voc@ po e ver6 ao clicar em um elemento a seleo o mesmo se torna livre e ele po e ser arrasta a para qualquer outra posio na lista a que elimita a e elementos no po e ser troca os em nosso e0emplo Sembora pertence. Ca a lista tambJm J

isso se=a possIvel usan o uma li#eira mo i"icao o c< i#oT. + resulta o e um movimento po e ser visto abai0oA

12*

+bviamente6 nosso or enao ain a no J persisti a. Para isso6 precisamos

e uma alterao em nosso

mo elos e a osA um campo que marque a posio o elemento na lista. %eramos uma mi#rao para istoA

ronaldo@minerva:~/tmp/gtd$ " ript/generate migration addApriorityAtoAa tion" exi"t" db/migrate reate db/migrate/'1&AaddApriorityAtoAa tion".rb

/ a e itamosA

12'

la"" Ldd=riority<oL tion" K L tive2e ord::Bigration def "elf.up addA olumn :a tion"J :po"itionJ :integer end def "elf.down removeA olumn :a tion"J :po"ition end end

A#ora que temos um campo6 po emos alterar o mJto o que estamos usan o para us;loA

la"" L tion K L tive2e ord::/a"e attrAprote ted : reatedAatJ : ompletedAat def done!%value( if L tive2e ord::4onne tionLdapter"::4olumn.valueAtoAboolean%value( "elf. ompletedAat ! Gate<ime.now el"e "elf. ompletedAat ! nil end writeAattribute%QdoneQJ value( end belong"Ato : ontext belong"Ato :pro-e t belong"Ato :u"er validate"Apre"en eAof :de" ription validate"Apre"en eAof : ontextAid validate"Apre"en eAof :pro-e tAid ,a"AandAbelong"AtoAmany :re"our e"J :order !. QnameQ def "elf.findAbyA"tatu"%doneJ limit ! nil( find :allJ : ondition" !. )Qdone ! UQJ done U 1 : '+J :in lude !. ):u"erJ :pro-e tJ : ontext+J :order !. Qa tion".po"itionJ a tion".de" riptionQJ :limit !. limit end end

?sso #arante que no tenhamos que nos preocupar com o uso a or enao quan o implementarmos o ao que precisamos no controller. A#ora6 precisamos mu ar o nosso partial para a icionar uma ao Ms nossas listasA

KY if a tion".anyU Y. Kul id!QKY if a tion".fir"t.doneU Y. ompletedAa tion"KY el"e Y. ontextAa tion"AKY! a tion".fir"t. ontext.id Y.KY end Y.Q. KY a tion".ea , do Ma tionM Y. Kli id!Q ontextAa tionAKY! a tion.id Y.Q. KY unle"" a tion.doneU Y. KY! ,e #AboxAtag Q ompleted)?Sa tion.idT+QJ a tion.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. a tion TJ :before !. Y%1lement.",ow%Qindi atorQ((J : omplete !. Y%1lement.,ide%Qindi atorQ(((TQ Y. KY end Y. KY! a tion.de" ription Y.Kbr. K"pan.

124

K"trong.=ro-e t:K/"trong. KY! a tion.pro-e t.name Y. KY if a tion.doneU Y. Kbr.K"trong.4ontext:K/"trong. KY! a tion. ontext.name Y. Kbr.K"trong.4ompleted Lt:K/"trong. KY! a tion. ompletedAat."trftime%QYm/Yd/YyQ( Y. KY end Y. K/"pan. K/li. KY end Y. K/ul. KY unle"" a tion".fir"t.doneU Y. KY! "ortableAelement%Q ontextAa tion"A?Sa tion".fir"t. ontext.idTQJ :url !. S :a tion !. QorderQJ :id !. a tion".fir"t. ontext.id T( Y. KY end Y. KY el"e Y. Kul id!Q ompletedAa tion"Q.K/ul. KY end Y.

/mbora na ao se=a ra>oavelmente "cil

escobrir qual J o elemento que estamos or enan o6 passar o i

iretamente "ica bem mais "cil. A implementao seriaA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true end end

A ao J bem simples. + c< i#o Qava-cript seriali>a os elementos6 removen o tu o que no se=a um I#ito

a os em um parLmetro cu=o nome J o i e ei0ar somente o i

a lista.

Recuperamos esse parLmetro6 que J meramente um arra, com os elementos em or em e coletamos esses os mesmos a "im e ca a um. /m se#ui a6 "a>emos um loop com esses i 6 recuperan o a ao e salvan o sua nova posio. Por "im6 no retornamos na a = que a ao visual = "oi e"etua a.

AGINDO COMO UMA LISTA


/mbora no tenhamos usa o essa "uncionali a e aqui6 por no termos necessi a e6 o Rails possui um mJto o que po e "a>er com que uma classe ha=a como uma lista em termos mo i"icarmos o nosso mo elo e a&es para o abai0o6 teremos issoA e mo elo e a os. -e

125

la"" L tion K L tive2e ord::/a"e a t"Aa"Ali"t :" ope !. H ontextAid ! ?S ontextAidT and done ! 'HJ : olumn !. Qpo"itionQ attrAprote ted : reatedAatJ : ompletedAat def done!%value( if L tive2e ord::4onne tionLdapter"::4olumn.valueAtoAboolean%value( "elf. ompletedAat ! Gate<ime.now el"e "elf. ompletedAat ! nil end writeAattribute%QdoneQJ value( end belong"Ato : ontext belong"Ato :pro-e t belong"Ato :u"er validate"Apre"en eAof :de" ription validate"Apre"en eAof : ontextAid validate"Apre"en eAof :pro-e tAid ,a"AandAbelong"AtoAmany :re"our e"J :order !. QnameQ def "elf.findAbyA"tatu"%doneJ limit ! nil( find :allJ : ondition" !. )Qdone ! UQJ done U 1 : '+J :in lude !. ):u"erJ :pro-e tJ : ontext+J :order !. Qa tion".po"itionJ a tion".de" riptionQJ :limit !. limit end end

A eclarao usa a no c< i#o acima cria uma sJrie e mJto os que permitem que a classe se comporte com uma lista quan o con=untos e elementos seus so retorna os. Bo e0emplo6 in icamos que a coluna no banco que in ica a posio J position6 que criamos anteriormente. ?n icamos tambJm um escopo para a operao queremos que a lista s< se=a vli a no escopo passamos para o parLmetro scope um "ra#mento a lista. A e0emplo o que entro e"inimos em A=a0 acima6 e um conte0to. Para isso6 a lista. e a&es no completa as

e -DL que J usa o para especi"icar os limites

/sse "ra#mento ser usa o em to as opera&es e lista. Bote que e"inimos esse "ra#mento com aspas simples. ?sso acontece porque estamos usan o interpolao e no queremos que ela acontea ime iatamente como aconteceria se estivessemos usan o aspas uplas. + resulta o so mJto os que po emos usar caso precisamos acessar um #rupo lista. )e=a no console como isso "uncionariaA e a&es com se "osse uma

ronaldo@minerva:~/tmp/gtd$ " ript/ on"ole Doading development environment. .. a tion" ! L tion.findAallAbyA ontextAidAandAdone%*J fal"e( !. )?KL tion:'xbRR &ae$ @attribute"!SQ ontextAidQ!.Q*QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.QRQJ QdoneQ!.Q'QJ QidQ!.Q5QJ Qde" riptionQ!.QL "imple te"t a tion.QJ Qu"erAidQ!.Q&QJ Qpo"itionQ!.Q1QJ

121

Q reatedAatQ!.Q&''*-'6-&$ 1$:53:5RQT.J ?KL tion:'xbRR &aa8 @attribute"!SQ ontextAidQ!.Q*QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.QRQJ QdoneQ!.Q'QJ QidQ!.Q8QJ Qde" riptionQ!.QFet anot,er "imple te"t a tion.QJ Qu"erAidQ!.Q&QJ Qpo"itionQ!.Q&QJ Q reatedAatQ!.Q&''*-'6-&* 18:11:3'QT.+ .. a tion"."ize !. & .. a tion")'+.fir"tU !. true .. a tion")1+.la"tU !. true .. a tion")1+.fir"tU !. fal"e .. a tion")'+.la"tU !. fal"e .. a tion")'+.moveAlower !. true .. a tion")'+.la"tU !. true .. a tion")'+.fir"tU !. fal"e .. a tion")'+.,ig,erAitem !. ?KL tion:'xbRRRe*5' @attribute"!SQ ontextAidQ!.Q*QJ Q ompletedAatQ!.nilJ Qpro-e tAidQ!.QRQJ QdoneQ!.Q'QJ QidQ!.Q8QJ Qde" riptionQ!.QFet anot,er "imple te"t a tion.QJ Qu"erAidQ!.Q&QJ Qpo"itionQ!.Q1QJ Q reatedAatQ!.Q&''*-'6-&* 18:11:3'QT. .. a tion")'+.moveAtoAtop !. true

Como po emos ver pelos e0emplos acima6 temos mJto os bem prticos para a operao "acili a e e criar sub;lin#ua#ens eclarativas6 muito aproveita a pelo Rails6 J um positivos o Rub,. /0istem outros

a lista. /ssa

os maiores pontos

ois mJto os similares que vem com o RailsA acts0as0tree6 que trans"orma um mo elo em o mesmo tema que6 ao contrrio a primeira6

uma rvore aninha aK e acts0as0nested0set6 uma variao a icionam comportamentos similares. Como qualquer outra passam e "ra#mentos simplici a e J que est to o o po er o Rub, e o Rails

J muito mais e"iciente na busca e muito menos e"iciente na atuali>ao a rvore. /0istem ain a plu#ins que as tJcnicas que vimos atJ a#ora6 elas no e"ini a. / nessa e c< i#o que trans"ormam a classe enquanto ela est sen o

A#ora que temos a nossa lista "unciona o6 po emos partir para al#o um pouco mais avana oA e itar e inserir novas a&es via A=a0. /mbora insero e e io se=a li an o com A=a0 vamos an ar um pouco mais eva#ar. Para usar a e io6 vamos primeiro mo i"icar a nossa vieG principal para e0ibir um "ormulrio na mesmaA ois aspectos a mesma moe a6 como estamos

K,1.8ext L tion"K/,1.

12!

KY! render :partial !. QeditQ Y. KY @a tion".groupAby%[: ontext(.ea , do M ontextJ a tion"M Y. Kdiv la""!QgroupQ id!Q ontextAKY! ontext.id Y.Q. K,&.KY! ontext.name Y.K/,&.

KY! render :partial !. Qa tion"QJ :ob-e t !. a tion" Y. K/div. KY end Y. Kdiv la""!QgroupQ.

K,&.4ompleted L tion"K/,&. KY! render :partial !. Qa tion"QJ :ob-e t !. @ ompletedAa tion" Y. K/div.

V mais "cil usar um partial porque po emos ter que mo i"icar o item via A=a06 e isso separa o que precisamos e maneira mais tranqRila. + partial seria al#o assimA

Kdiv

la""!QeditQ id!QeditAformQ.

K,&.8ext L tionK/,&. Kdiv la""!Qedit- ontent"Q.

KY formAremoteAfor :itemJ @a tionJ :url !. S :a tion !. QeditQ T do MformM Y. Kp. Klabel for!QitemAde" riptionQ.Ge" ription:K/label.Kbr. KY! form.textAarea Qde" riptionQJ :row" !. 3 Y. K/p. Kp. Klabel for!QitemA ontextAidQ.4ontext:K/label.Kbr. KY! form."ele t Q ontextAidQJ @ ontext"J :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. Klabel for!QitemApro-e tAidQ.=ro-e t:K/label.Kbr. KY! form."ele t Qpro-e tAidQJ @pro-e t"J :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. K/p. KY end Y. K/div. K/div.

Bote o uso

o mJto o form0remote0for. AtJ o momento6 usamos o mJto o start0form0tag para nossos o "ormulrio em si6 precisan o e

"ormulrios. /sse J um mJto o simples6 que #era somente o ta# end0form0tag para "ech;lo.

/0iste um outro mJto o6 chama o form0for Scom sua verso remota form0remote0for6 mostra a acimaT6 que recebe um bloco e nesse bloco J capa> e #erar os campos necessrios6 usan o mJto os internos como
125

emonstra o acima. AlJm

isso6 essa verso

e #erao

e "ormulrio tambJm J capa>

e usar classes

au0iliares para "ormatar in ivi ualmente os campos a serem #era os. A verso remota tem a Pnica i"erena e usar A=a0 para enviar o campos6 e uma maneira similar a remote0function. Para "acilitar o nosso tutorial6 no vamos inserir em to as as nossa chama as A=a0 o c< i#o necessrio para mostrar e escon er o in ica or e ativi a e. ?ncluir o in ica or em to as as chama as J uma boa i Jia em qualquer aplicao A=a06 mas para "ins e e0emplo aqui vamos i#norar essa questo. / nosso controller "icaria assimA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true end end

Bote que6 temporariamente6 no estamos utili>an o nenhum ob=eto em nosso "ormulrio #era o.

TRANSFORMANDO UM MODELO DE DADOS


/ssa J a se#un a ve> que usamos o c< i#o acima para #erar listas e itens a serem usa os em elementos

select em "ormulrios. Com base no princIpio DRC6 seria interessante mover esse c< i#o para um local on e
o mesmo pu esse ser reusa o. .ma soluo J acrescentar um mJto o como o abai0o ao mo elo e a osA

def a"AdropAdown%order !. QnameQ( find%:allJ :order !. order(. olle t S MiM )i.nameJ i.id+ T end

-imples6 embora obviamente tenha que ser repeti a para ca a mo elo em que tivermos interesse em al#o similar. Po erIamos mov@;la para um helper6 com uma pequena mo i"icao e evitar a repetio.

122

.ma outra soluo6 melhor ain a6 seria criar uma espJcie implementar a se#uinte "ormaA

e acts0as0drop0down6 que po eriamos

module X<G module L t" module GropGown def "elf.appendAfeature"%ba"e( ba"e.extend%4la""Bet,od"( end module 4la""Bet,od" def a t"Aa"AdropAdown%option" ! ST( la""Aeval KK-1:9 def "elf.a"AdropAdown find%:allJ :order !. Q?Soption"): olumn+TQ(. olle t S MiM )i.?Soption"): olumn+TJ i.id+ end 1:9 end end end end end L tive2e ord::/a"e. la""Aeval do in lude X<G::L t"::GropGown end

Bo c< i#o acima6 estamos

e"inin o um m< ulo &*L::-cts::LropLown. /sse m< ulo usa o mJto o e criar na classe

append0features6 que = e0plicamos antes6 para a icionar novas implementa&es a uma classe base. -e voc@ reparar as Pltimas tr@s linhas6 ver que estamos incluin o o m< ulo que acabamos base o ActiveRecor 6 a qual to os nossos mo elos erivam. + nosso mJto o append0features/no "a> mais na a classe base o ActiveRecor . /sses mJto os esto "a>6 por sua ve>6 J nossos mo elos e"ini os em um m< ulo interno6 chama o 7lass2ethods. + que esse m< ulo interno e"inir uma e0tenso chama a acts0as0drop0down6 que ao ser chama a6 trans"ormar ese=amos aqui6 ou se=a6 intro u>ir um mJto o "inal que po emos usar o que usar o mJto o extend6 presente em to as as

classes Rub,6 para incluir al#uns novos mJto os na classe que esta mo i"ican o que6 como vimos acima6 J a

a maneira que

para #era nossos a os. V uma ca eia um pouco complica a e se se#uir a princIpio6 mas estu an o o c< i#o voc@ ver que ela se

torna clara em pouco tempo. /sse mJto o6 acts0as0drop0down6 "a> uma coisa bem simples6 ele interpreta uma strin# no conte0to a classe6 que contJm a e"inio "inal e um mJto o6 com base nos parLmetros que passamos. V mais "cil usar uma strin# aqui para evitar as re#ras e conte0to o uso e um bloco.
*$$

+ mJto o que

e"inimos J o nosso as0drop0down6 visto anteriormente6 mas a#ora em uma verso #enJrica.

Duan o o mJto o class0e!al/ro a6 ele e0ecuta a strin# que lhe "oi passa a no conte0to a classe6 #eran o um mJto o "inal que contJm o c< i#o que precisamos. + mJto o acts0as0drop0down recebe um parLmetro nomea o6 column6 que J a coluna pela qual queremos or enar e que queremos e0ibir em nossos "ormulrios. Para "acilitar o enten imento6 ve=a o uso em um mo elo e a osA o m< ulo

la"" 4ontext K L tive2e ord::/a"e in lude X<G::Luditing a t"Aa"AdropAdown : olumn !. QnameQ attrAprote ted :u"erAid validate"Apre"en eAof :name validate"Auni@uene""Aof :name validate"Apre"en eAof :u"erAid ,a"Amany :a tion" end

Consi eran o o c< i#o acima6 so as tr@s linhas "inais que nos permitem usar acts0as0drop0down /sem precisar acts0as0audited. Bo momento em que a classe J e al#o como "i>emos na linha

iretamente o mJto o a eclarao.

iretamente acima

Po erIamos usar a mesma tJcnica para mu ar a linha include / &*L::-uditing para al#o como

e"ini a6 o mJto o acts0as0drop0down /ro a6 #eran o por sua ve> um

mJto o as0drop0down/na classe6 que po emos usar em nosso controller a se#uinte maneiraA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @ ontext" ! 4ontext.a"AdropAdown @pro-e t" ! =ro-e t.a"AdropAdown end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1(

*$1

end render :not,ing !. true end end

Relembran o a ca eia6 temosA 1T + m< ulo %:DAAActsAADropDoGn J inclui o na classe base o ActiveRecor 6 -cti!e1ecord::Gase. *T Ao ser incluin o6 o m< ulo acima esten e a classe base a icionan o um mJto o e classe chama o acts0as0drop0down6 que po e ser invoca o para e"etuar outra mo i"icao na classe. Com isso conse#uimos que a mo i"icao s< se=a aplica a se o mJto o "or realmente invoca o6 o que "a>emos nos mo elos e nossa escolha. ?sso usa uma proprie a e o Rub, que J a mo i"icao inLmica e uma classe enquanto ela est sen o eclara a6 'T Caso o mJto o se=a invoca o6 ele e0ecuta uma eclarao no conte0to a classe que #era um e mJto o "inal e classe as0drop0down6 customi>a o especialmente para a classe. 4T /sse mJto o po e ser usa o livremente em controllers e vieGs6 "uncionan o sem a necessi a e qualquer outra "orma e con"i#urao. /ssa tJcnica e mo i"icao e classes J muito po erosa e po erIamos us;la e aument;la as maneiras pa ro e inumeras

maneiras. De "ato6 po e;se consi erar que basicamente to as as caracterIsticas usan o tJcnicas similares6 consi eran o que essa J uma classes no Rub,.

o Rails so implementas e e"etuar mu anas em

?sso acontece porque a lin#ua#em no possui6 proposita amente6 herana mPltipla. Assim6 a maior parte o que J "eito para incrementar uma classe J atravJs e m< ulos6 ou mi0ins na terminolo#ia o Rub,. + pr<prio mJto o group0by6 que usamos anteriormente6 J um mi0in a iciona o a outro mi0in que e"ine enumera&es. +bviamente6 antes e po emos ro ar o c< i#o precisamos mo i"icar nosso arquivo e con"i#urao

en!ironment.rb como visto abai0o e reiniciar o nosso servi orA

? /e "ure to re"tart your web "erver w,en you modify t,i" file. ? On omment below to for e 2ail" into produ tion mode w,en ? you donHt ontrol web/app "erver and anHt "et it t,e proper way ? 18Z)H2L7D>A18ZH+ MM! Hprodu tionH ? >pe ifie" gem ver"ion of 2ail" to u"e w,en vendor/rail" i" not pre"ent 2L7D>AX1BAZ12>7:8 ! H1.1.*H ? /oot"trap t,e 2ail" environmentJ framewor#"J and default re@uire 9ile.-oin%9ile.dirname%AA97D1AA(J HbootH( onfiguration

2ail"::7nitializer.run do M onfigM ? >etting" in onfig/environment"/P ta#e pre eden e t,o"e "pe ified ,ere ? >#ip framewor#" youHre not going to u"e %only wor#" if u"ing vendor/rail"( ? onfig.framewor#" -! ) :a tionAwebA"ervi eJ :a tionAmailer +

*$*

? Ldd additional load pat," for your own u"tom dir" onfig.loadApat," N! Y0% ?S2L7D>A2::<T/extra" ( ? 9or e all environment" to u"e t,e "ame logger level ? %by default produ tion u"e" :infoJ t,e ot,er" :debug( ? onfig.logAlevel ! :debug ? O"e t,e databa"e for "e""ion" in"tead of t,e file "y"tem ? % reate t,e "e""ion table wit, Hra#e db:"e""ion": reateH( ? onfig.a tionA ontroller."e""ionA"tore ! :a tiveAre ordA"tore ? O"e >CD in"tead of L tive 2e ordH" " ,ema dumper w,en reating t,e te"t databa"e. ? <,i" i" ne e""ary if your " ,ema anHt be ompletely dumped by t,e " ,ema dumperJ ? li#e if you ,ave on"traint" or databa"e-"pe ifi olumn type" ? onfig.a tiveAre ord." ,emaAformat ! :"@l ? L tivate ob"erver" t,at ",ould alway" be running ? onfig.a tiveAre ord.ob"erver" ! : a ,erJ :garbageA olle tor ? Ba#e L tive 2e ord u"e O<4-ba"e in"tead of lo al time ? onfig.a tiveAre ord.defaultAtimezone ! :ut ? >ee 2ail"::4onfiguration for more option" end ? ? ? ? ? ? ? ? Ldd new infle tion rule" u"ing t,e following format %all t,e"e example" are a tive by default(: 7nfle tor.infle tion" do Minfle tM infle t.plural /^%ox($/iJ HE1enH infle t."ingular /^%ox(en/iJ HE1H infle t.irregular Hper"onHJ HpeopleH infle t.un ountable Yw% fi", ",eep ( end

? 7n lude your appli ation onfiguration below re@uire Qu"erAfilter.rbQ re@uire Qauditing.rbQ re@uire Qa t"Aa"AdropAdown.rbQ L tionBailer::/a"e."erverA"etting" ! S :addre"" !. Qmail.yourdomain. omQJ :domain !. Qyourdomain. omQJ :u"erAname !. Qu"er@yourdomain. omQJ :pa""word !. QPPPPPPQJ :aut,enti ation !. :login T

/ssa soluo J bem melhor

o que as primeiras que pensamos6 mas ain a carece

e um

etalheA ser

portvel. -e quisermos us;la em outros pro=etos6 teremos copiar os arquivos e mo i"icar nossa con"i#urao. A soluo i eal seria empacotar o m< ulo com um plu#in6 que po eria ser simplesmente ei0a o no iret<rio apropria o6 "a>en o com que a mu ana estivesse automaticamente isponIvel para aplicao sem mo i"ica&es e0plIcitas e con"i#urao. + mJto o usa o tambJm J um pouco limita o no senti o o que o Pnico parLmetro que po e ser in"orma o J o nome e um atributo simples. /m um caso #eral6 haveria a possibili a e e usar um mJto o qualquer o ob=eto para te0to e outro mJto o para or enao6 con i&es6 limites6 e assim por iante. A icionar isso "ica como um e0ercIcio para o leitor.

*$'

CONTINUANDO COM AJAX


A#ora que temos nossas peas6 precisamos somente default.css6 a icionan o o "ra#mento e c< i#o abai0oA e um pequena alterao em nosso arquivo

div.group S margin-rig,t: &3'px5 T div.edit S border: 1px "olid ? float: rig,t5 widt,: &&'px5 T div.edit- ontent" S margin: 1'px5 T div.edit ,& S padding: 5px5 margin: 'px5 border-bottom: 1px "olid ? ba #ground- olor: ?ddd5 font-"ize: 11'Y5 T div.edit "ele tJ div.edit textarea S widt,: 16'px5 T

+ resulta o "inal

e tu o o que "i>emos atJ a#ora6 incluin o o

esvio acima para mostrar com um m< ulo

po e ser cria o6 J o se#uinteA

*$4

A#ora que temos o nosso "ormulrio6 po emos comear a pro#ramao A=a0 o mesmo. :emos que consi erar vrias situa&es. +lhan o a tela acima6 por e0emplo6 o que acontece quan o a icionarmos uma ao em um conte0to que no est sen o e0ibi o na p#ina` Como po emos e0ibir nossas vali a&es` Para resolvermos isso6 vamos ter que "a>er al#uma mo i"ica&es ra>oveis em nosso c< i#o. (as6 para comearmos6 vamos simplesmente consi erar a e0ist@ncia o conte0to na p#ina. Q temos o nosso "ormulrio remoto. Precisamos a#ora criar a nossa ao6 que salvar o nosso ob=eto e o e0ibir apropria amenteA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @ ontext" ! 4ontext.a"AdropAdown @pro-e t" ! =ro-e t.a"AdropAdown

*$5

end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true end def edit @a tion ! L tion. reate%param"):item+.merge%S :done !. fal"e T(( unle"" @a tion.validU render :not,ing !. true end end end

+ que "a>emos na ao J tentar criar e salvar os nossos

a os. -e no conse#uirmos6 temporariamente

i#noramos o erro. Bo e0emplo acima6 a icionamos o atribute done como "also para que o mesmo receba uma valor no nulo6 = que ele no est sen o envia o o "ormulrio. A#ora precisamos e um template RQ- que nos permita a icionar uma ao recJm cria a M sua lista e

conte0to correspon ente. Para isso criamos a vieG edit.r%sA

page.in"ertA,tml :bottomJ Q ontextAa tion"A?S@a tion. ontext.idTQJ :partial !. QitemQJ :ob-e t !. @a tion page.vi"ualAeffe t :,ig,lig,tJ Q ontextAa tionA?S@a tion.idTQJ :duration !. 3.5

/stamos mais uma ve> usan o um partial para nosso conteP o6 a icionan o 4:(L a um elemento = e0istente. Como mencionamos acima6 vamos li ar p#ina. /sse partial seria al#o assim6 e"ini o no arquivo 0item.rhtmlA epois com o caso e um conte0to que no est na

Kli id!Q ontextAa tionAKY! item.id Y.Q. KY unle"" item.doneU Y. KY! ,e #AboxAtag Q ompleted)?Sitem.idT+QJ item.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. item TJ :before !. Y%1lement.",ow%Qindi atorQ((J : omplete !. Y%1lement.,ide%Qindi atorQ(((TQ Y. KY end Y. KY! item.de" ription Y.Kbr. K"pan. K"trong.=ro-e t:K/"trong. KY! item.pro-e t.name Y. KY if item.doneU Y. Kbr.K"trong.4ontext:K/"trong. KY! item. ontext.name Y. Kbr.K"trong.4ompleted Lt:K/"trong. KY! item. ompletedAat."trftime%QYm/Yd/YyQ( Y.

*$1

KY end Y. K/"pan. K/li.

+ que vamos aqui J na a mais

o que tInhamos em nosso outro partial6

e"ini o no arquivo

0actions.rhtml. Po emos6 conseqRentemente6 mu ar esse arquivo paraA

KY if a tion".anyU Y. Kul id!QKY if a tion".fir"t.doneU Y. ompletedAa tion"KY el"e Y. ontextAa tion"AKY! a tion".fir"t. ontext.id Y.KY end Y.Q. KY! render :partial !. QitemQJ : olle tion !. a tion" Y. K/ul. KY unle"" a tion".fir"t.doneU Y. KY! "ortableAelement%Q ontextAa tion"A?Sa tion".fir"t. ontext.idTQJ :url !. S :a tion !. QorderQJ :id !. a tion".fir"t. ontext.id T( Y. KY end Y. KY el"e Y. Kul id!Q ompletedAa tion"Q.K/ul. KY end Y.

V claro que usar muitos partials ocasiona uma per a

e per"ormance. (as no precisamos nos preocupar

com isso no momento = que isso seria uma otimi>ao prematura. .m princIpio bom o esenvolvimento e aplica&es6 se=a em Rails ou no6 J "a>er o que seria mais ele#ante e mais le#Ivel primeiro e epois otimi>ar e acor o com a necessi a e. /m termos e otimi>ao6 e0istem e>enas e op&es que po eriam ser consi era as. (as6 quaisquer que

se=am s< evem ser utili>a as epois a i enti"icao e um problema real para evitar per as e tempo. Para a maior parte as aplica&es6 a veloci a e e qualquer p#ina ser boa o su"iciente porque nem a

car#a e a os nem a car#a e usurios sero altas emais para causar al#um problema. / mesmo antes e consi eramos a&es complica as para salvar um ou outro se#un o e per"ormance aqui e ali6 po em e0istir solu&es mais simples presentes no Rails. De qualquer "orma6 aplica&es A=a0 #eralmente balanam um #asto a ca a ve> que uma mu ana J "eita. Bo caso acima ob=eto e e nossa p#ina6 por e0emplo6 em muitas as a&es estaremos tratan o com apenas um e per"ormance maior por causa e

vrios partials com um tr"e#o menor e a os na p#ina6 por evitarem recarre#ar os a os completos to a

a os6 e tentar otimi>ar qualquer coisa relaciona a as a&es e"etua as em um Pnico ob=eto seria

provavelmente um imenso esper Icio e ener#ia. )oltan o M nossa aplicao6 o resulta o6 ao a icionarmos uma ao em um conte0to = e0istente JA

*$!

Precisamos a#ora apenas

e re"inamentos para melhorar o que = "i>emos. A primeira coisa J limpar o

"ormulrio em caso e sucesso. Po emos "a>er isso a se#uinte maneiraA

page.in"ertA,tml :bottomJ Q ontextAa tion"A?S@a tion. ontext.idTQJ :partial !. QitemQJ :ob-e t !. @a tion page.vi"ualAeffe t :,ig,lig,tJ Q ontextAa tionA?S@a tion.idTQJ :duration !. 3.5 page.repla e QeditAformQJ :partial !. QeditQ

+ que requer uma mu ana em nosso controllerA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @ ontext" ! 4ontext.a"AdropAdown @pro-e t" ! =ro-e t.a"AdropAdown

*$5

end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true end def edit @ ontext" ! 4ontext.a"AdropAdown @pro-e t" ! =ro-e t.a"AdropAdown @a tion ! L tion. reate%param"):item+.merge%S :done !. fal"e T(( unle"" @a tion.validU render :not,ing !. true end end end

Bo caso acima6 como encapsulamos a nossa #era&es os a os necessrios e conte0to e pro=eto6 no seria uma violao e c< i#o. + resulta o seria uma vieG assimA a estratJ#ia ()C mover esses chama as para entro a vieG6 economi>an o uma repetio

Kdiv

la""!QeditQ id!QeditAformQ.

K,&.8ext L tionK/,&. Kdiv la""!Qedit- ontent"Q.

KY formAremoteAfor :itemJ @a tionJ :url !. S :a tion !. QeditQ T do MformM Y. Kp. Klabel for!QitemAde" riptionQ.Ge" ription:K/label.Kbr. KY! form.textAarea Qde" riptionQJ :row" !. 3 Y. K/p. Kp. Klabel for!QitemA ontextAidQ.4ontext:K/label.Kbr. KY! form."ele t Q ontextAidQJ 4ontext.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. Klabel for!QitemApro-e tAidQ.=ro-e t:K/label.Kbr. KY! form."ele t Qpro-e tAidQJ =ro-e t.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. K/p. KY end Y.

*$2

K/div. K/div.

Com isso6 as linhas recJm;inseri as po eriam ser removi as o controller6 sem pre=uI>o para a manuteno e le#ibili a e. Continuan o em nossas melhorias6 J hora e intro u>ir vali ao em nosso "ormulrio. Po emos "a>er isso

com uma mu ana relativamente simples. Primeiro6 em nossa vieGA

Kdiv

la""!QeditQ id!QeditAformQ.

K,&.8ext L tionK/,&. KY! errorAme""age"Afor Qa tionQ Y. Kdiv la""!Qedit- ontent"Q.

KY formAremoteAfor :itemJ @a tionJ :url !. S :a tion !. QeditQ T do MformM Y. Kp. Klabel for!QitemAde" riptionQ.Ge" ription:K/label.Kbr. KY! form.textAarea Qde" riptionQJ :row" !. 3 Y. K/p. Kp. Klabel for!QitemA ontextAidQ.4ontext:K/label.Kbr. KY! form."ele t Q ontextAidQJ 4ontext.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. Klabel for!QitemApro-e tAidQ.=ro-e t:K/label.Kbr. KY! form."ele t Qpro-e tAidQJ =ro-e t.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. K/p. KY end Y. K/div. K/div.

(u an o em se#ui a o nosso template R-QA

if @a tion.validU page.in"ertA,tml :bottomJ Q ontextAa tion"A?S@a tion. ontext.idTQJ :partial !. QitemQJ :ob-e t !. @a tion page.vi"ualAeffe t :,ig,lig,tJ Q ontextAa tionA?S@a tion.idTQJ :duration !. 3.5 @a tion ! nil end page.repla e QeditAformQJ :partial !. QeditQ

-< a icionamos um item se o mesmo "or vli o6 e circunstLncia.

epois ren eri>amos o nosso partial em qualquer

*1$

A chave aqui J que se tivermos um valor no ob=eto6 o partial ren eri>ar um "ormulrio preenchi o6 caso contrrio o "ormulrio vir va>io. Como estamos usan o uma varivel e ren eri>ar o "ormulrio em caso e instLncia6 >eramos a mesma antes e uma insero positiva. A#ora s< precisamos mu ar o nosso

controllerA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true end def edit value" ! param"):item+.merge%S :done !. fal"e T( value")Q ontextAidQ+ ! QQ if value")Q ontextAidQ+ [[ value")Q ontextAidQ+."tart"Awit,U%Q--Q( value")Qpro-e tAidQ+ ! QQ if value")Qpro-e tAidQ+ [[ value")Qpro-e tAidQ+."tart"Awit,U%Q--Q( @a tion ! L tion. reate%value"( end end

+ c< i#o acima se

eve a uma pequena caracterIstica

a biblioteca Protot,pe usa a para o Rails. Ao e elementos o tipo select6 se o item seleciona o o que nave#a ores "a>em

seriali>ar "ormulrios para envio via Qava-cript6 no caso normalmente. ?sso J o que tratamos no c< i#o acima.

no tiver um valor associa o a biblioteca envia o te0to6 ao contrrio

Bo nosso "ormulrio6 isso acontece porque os elementos select que estamos usan o contJm um valor va>io para o primeiro elemento6 que J #era o pelo parLmetro prompt para nos ar uma usabili a e maior. .ma soluo para o problema seria mo i"icar a biblioteca para no ter esse comportamento por pa ro. + inconveniente seria ter que manter esse patch a ca a atuali>ao a mesma. .ma outra soluo seria criar um "iltro para automaticamente limpar os nossos parLmetros se "or o caso. / uma terceira soluo seria no usar o parLmetro prompt6 usan o include0blan3 ao invJs isso6 com uma pequena per a e usabili a e. + resulta o6 com a vali ao6 J o se#uinteA

*11

A#ora precisamos a icionar o caso em que um conte0to que no est sen o e0ibi o na p#ina6 por no possuir nenhuma ao no completa a6 recebe uma ao. (u amos a nossa vieG primriaA

K,1.8ext L tion"K/,1. KY! render :partial !. QeditQ Y. Kdiv id!Q ontext"Q.

*1*

KY @a tion".groupAby%[: ontext(.ea , do M ontextJ a tion"M Y. KY! render :partial !. Q ontextQJ :ob-e t !. ontextJ :lo al" !. S :a tion" !. a tion" T Y. KY end Y. K/div. Kdiv la""!QgroupQ.

K,&.4ompleted L tion"K/,&. KY! render :partial !. Qa tion"QJ :ob-e t !. @ ompletedAa tion" Y. K/div.

/6 como conseqR@ncia6 criamos uma novo partial6 e"ini o no arquivo 0context.rhtmlA

Kdiv

la""!QgroupQ id!Q ontextAKY! ontext.name Y.K/,&.

ontext.id Y.Q.

K,&.KY!

KY! render :partial !. Qa tion"QJ :ob-e t !. a tion" Y. K/div.

Por "im6 alteramos o nosso template R-QA

if @a tion.validU page KK Qif %typeof%$%H ontextA?S@a tion. ontext.idTH(( !! HundefinedH( SQ page.in"ertA,tml :topJ Q ontext"QJ :partial !. Q ontextQJ :ob-e t !. @a tion. ontextJ :lo al" !. S :a tion" !. @a tion. ontext.a tion" T page KK QT el"e SQ page.in"ertA,tml :bottomJ Q ontextAa tion"A?S@a tion. ontext.idTQJ :partial !. QitemQJ :ob-e t !. @a tion page KK QTQ page.vi"ualAeffe t :,ig,lig,tJ Q ontextAa tionA?S@a tion.idTQJ :duration !. 3.5 @a tion ! nil end page.repla e QeditAformQJ :partial !. QeditQ

Bo e0emplo acima6 precisamos saber se o conte0to = e0iste na p#ina. Para isso6 usamos um pouco Qava-cript ireto6 veri"ican o se h um ob=eto com o i

que precisamos na p#ina. Caso e0ista6

simplesmente a icionamos a ao. Caso contrrio6 ren eri>amos o conte0to completo e o inserimos no topo a lista #eral e conte0tos. + resulta o "inal J o que queremos6 com ois problemas simplesA + primeiro J que tanto as a&es como conte0tos inseri os esto potencialmente "ora acor o com os critJrios que estabelecemos = que estamos inserin o o resulta o se=a um pouco mais caro em termos vli a. + se#un o problema J termos que "orar a varivel ?action a assumir um valor nulo antes e usar uma varivel e e0ibirmos o e or enao e

e nossas chama as em

locais "i0os. A soluo para isso seria ren eri>amos as se&es completas que precisamos6 mesmo que isso e per"ormance. -e a or em "or muito importante6 essa J uma soluo

"ormulrio para o caso e queremos um "ormulrio va>io. + melhor seria usar a pr<pria conveno o Rails e"ini a para o pr<prio partial. + problema6 nesse caso6 J que estamos usan o
*1'

error0messages0for6 que espera uma varivel

e instLncia. Para "ins

o nosso tutorial isso no tem muita

importLncia. (as para um aplicao real6 seria interessante uma re e"inio esse mJto o. + resulta o a a io e uma ao em um conte0to no e0istente na p#ina J o se#uinteA

-e voc@ tentou usar a lista para reor enar um elemento epois a a io e um item6 reparou que a mesma para e "uncionar. /sse J o compartamento normal e uma lista quan o um novo elemento J a iciona o M epois e uma mo i"icao na mesma6 corri#in o o mesma. Para corri#ir isso6 basta reiniciali>ar a lista

template RQ- para e ioA


*14

if @a tion.validU page KK Qif %typeof%$%H ontextA?S@a tion. ontext.idTH(( !! HundefinedH( SQ page.in"ertA,tml :topJ Q ontext"QJ :partial !. Q ontextQJ :ob-e t !. @a tion. ontextJ :lo al" !. S :a tion" !. @a tion. ontext.a tion" T page KK QT el"e SQ page.in"ertA,tml :bottomJ Q ontextAa tion"A?S@a tion. ontext.idTQJ :partial !. QitemQJ :ob-e t !. @a tion page KK QTQ page.vi"ualAeffe t :,ig,lig,tJ Q ontextAa tionA?S@a tion.idTQJ :duration !. 3.5 page."ortable Q ontextAa tion"A?S@a tion. ontext.idTQJ :url !. S :a tion !. QorderQJ :id !. @a tion. ontext.id T @a tion ! nil end page.repla e QeditAformQJ :partial !. QeditQ

/ uma Pltima melhoria que po emos "a>er antes "orma e cancelar a e io quan o o usurio e io6 em 0edit.rhtmlA

e partirmos para o nosso pr<0imo t<pico J ter al#uma e mo i"icar o nosso partial e

ese=ar. Para isso6 precisamos

Kdiv

la""!QeditQ id!QeditAformQ.

K,&.8ext L tionK/,&. KY! errorAme""age"Afor Qa tionQ Y. Kdiv la""!Qedit- ontent"Q.

KY formAremoteAfor :itemJ @a tionJ :url !. S :a tion !. QeditQ T do MformM Y. Kp. Klabel for!QitemAde" riptionQ.Ge" ription:K/label.Kbr. KY! form.textAarea Qde" riptionQJ :row" !. 3 Y. K/p. Kp. Klabel for!QitemA ontextAidQ.4ontext:K/label.Kbr. KY! form."ele t Q ontextAidQJ 4ontext.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. Klabel for!QitemApro-e tAidQ.=ro-e t:K/label.Kbr. KY! form."ele t Qpro-e tAidQJ =ro-e t.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#AtoAremote Q4an elQJ :url !. S :a tion !. Q an elQ T Y. K/p. KY end Y. K/div. K/div.

/ epois isso6 a icionar uma ao ao nosso controllerA

la"" ;ome4ontroller K Lppli ation4ontroller

*15

def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true end def edit value" ! param"):item+.merge%S :done !. fal"e T( value")Q ontextAidQ+ ! QQ if value")Q ontextAidQ+ [[ value")Q ontextAidQ+."tart"Awit,U%Q--Q( value")Qpro-e tAidQ+ ! QQ if value")Qpro-e tAidQ+ [[ value")Qpro-e tAidQ+."tart"Awit,U%Q--Q( @a tion ! L tion. reate%value"( end def end end an el

7inali>an o com um novo template RQ- para a ao6 #eran o uma vieG chama a cancel.r%sA

page.repla e QeditAformQJ :partial !. QeditQ

.ma outra "orma que no e0istiria.

e "a>er o cancelamento seria ren eri>ar

iretamente o partial6 pulan o o template RQ-6

Para isso6 nosso "ormulrio e e io "icaria um pouco i"erenteA

Kdiv id!QeditAformA ontainerQ. Kdiv la""!QeditQ id!QeditAformQ.

K,&.8ext L tionK/,&. KY! errorAme""age"Afor Qa tionQ Y. Kdiv TJ la""!Qedit- ontent"Q.

KY formAremoteAfor :itemJ @a tionJ :,tml !. S :a tion !. urlAfor%:a tion !. Q"aveQJ :id !. @a tion( :url !. S :a tion !. Q"aveQJ :id !. @a tion T do MformM Y. Kp. Klabel for!QitemAde" riptionQ.Ge" ription:K/label.Kbr. KY! form.textAarea Qde" riptionQJ :row" !. 3 Y. K/p.

*11

KY if W@a tion MM @a tion.newAre ordU Y. Kp. Klabel for!QitemA ontextAidQ.4ontext:K/label.Kbr. KY! form."ele t Q ontextAidQJ 4ontext.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. Klabel for!QitemApro-e tAidQ.=ro-e t:K/label.Kbr. KY! form."ele t Qpro-e tAidQJ =ro-e t.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. KY end Y. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#AtoAremote Q4an elQJ :update !. QeditAformA ontainerQJ :url !. S :a tion !. Q an elQ T Y. K/p. KY end Y. K/div. K/div. K/div.

:ambJm terIamos uma li#eira mo i"icao em nosso controllerA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+.g"ub%/)^'-6+/J QQ(( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true end def edit @a tion ! param"):id+ U L tion.find%param"):id+( : L tion.new end def "ave value" ! param"):item+.merge%S :done !. fal"e T( value")Q ontextAidQ+ ! QQ if value")Q ontextAidQ+ [[ value")Q ontextAidQ+."tart"Awit,U%Q--Q( value")Qpro-e tAidQ+ ! QQ if value")Qpro-e tAidQ+ [[ value")Qpro-e tAidQ+."tart"Awit,U%Q--Q( @a tion ! param"):id+ U L tion.update%param"):id+J value"( : L tion. reate%value"( re"pondAto do Mwant"M want".-" want".,tml do if @a tion.validU

*1!

redire tAto :a tion !. QindexQ el"e index render :a tion !. QindexQ end end end end def an el render :partial !. QeditQ end def delete @a tion ! L tion.find%param"):id+( @a tion.de"troy @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end end

A tItulo e observao6 note que os e0emplos se#uintes desfazem essa mo i"icao. A maneira usa a acima "a> uso e uma caracterIstica as invoca&es A=a0 reali>a as no Rails que J a e"ine o elemento 4:(L que receber o

possibili a e e6 ao invJs e retornar Qava-cript6 retornar um "ra#mento e 4:(L e atuali>ar iretamente a p#ina com o mesmo. + parLmetro update6 no e0emplo acima6 conteP o. Precisamos e um elemento superior porque a substituio J "eita somente no conteP o e0terno.

+ parLmetro update po e tambJm iscriminar entre sucesso e "alha usan o a se#uinte con"i#uraoA

:update !. S :"u

e"" !. Qid1QJ :failure !. Qid&Q T

Bo caso acima6 se a ao retornar um c< i#o 4::P pelo outro parLmetro J que ser atuali>a o.

e suceso6 o elemento com o i

especi"ica o pelo sub; J especi"ica o

parLmetro success J que receber o conteP o retorna oK caso contrrio6 o elemento cu=o i

As chama as remotas no Rails possuem vrias outras caracterIsticas que #astarIamos muito tempo para e0plorar aqui e cu=as escri&es po em ser encontra as na ocumentao e em outros tutoriais mais e parLmetros customi>a os para as a&es especI"icos. /ntre essas caracterIstiscas incluem;se a passa#em

no servi or6 acompanhamento o processo completo e requisio6 tratamento e con"irma&es e uma sJrie e outras possibili a es que nos permitem re"inar bastante a invocao o mJto o remoto. ?sso termina nossas melhorias. Depois e termos a insero "uncionan o6 po emos trabalhar com a e io e remoo e a&es e0istentes. Antes e partirmos para isso porJm6 uma icaA e0iste um plu#in para o Rails6 chama o .nobtrusive e #erar c< i#o Qava-cript

Qava-cript Shttp://www.u%sMrails.comT que po e a=u ar bastante na hora interpola o com uma p#ina para invocar lin8s6 "un&es e "ormulrios remotos.

*15

)amos comear com a e0cluso e um item6 que se#ue uma linha muito similar M

e marcar o mesmo como

completo. (o i"icamos o nosso partial que #erar um item para incluir um lin8 remoto para a aoA

Kli id!Q ontextAa tionAKY! item.id Y.Q. KY unle"" item.doneU Y. KY! ,e #AboxAtag Q ompleted)?Sitem.idT+QJ item.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. item TJ :before !. Y%1lement.",ow%Qindi atorQ((J : omplete !. Y%1lement.,ide%Qindi atorQ(((TQ Y. KY end Y. KY! item.de" ription Y. KY unle"" item.doneU Y. KY! lin#AtoAremote Q)G+QJ S :url !. S :a tion !. QdeleteQJ :id !. item TJ : onfirm !. QLre you "ureUQ TJ S : la"" !. Qa tion-lin#Q T Y. KY end Y. Kbr. K"pan. K"trong.=ro-e t:K/"trong. KY! item.pro-e t.name Y. KY if item.doneU Y. Kbr.K"trong.4ontext:K/"trong. KY! item. ontext.name Y. Kbr.K"trong.4ompleted Lt:K/"trong. KY! item. ompletedAat."trftime%QYm/Yd/YyQ( Y. KY end Y. K/"pan. K/li.

Acompanha o o se#uinte "ra#mento C-- a ser a iciona o em nosso arquivo default.cssA

a.a tion-lin# S text-de oration: none5 font-"ize: "maller5 border-bottom: 1px da",ed ?6665 olor: ?***5 T

A#ora que temos a nossa chama a6 po emos implementar a nossa aoA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true end def edit value" ! param"):item+.merge%S :done !. fal"e T(

*12

value")Q ontextAidQ+ ! QQ if value")Q ontextAidQ+ [[ value")Q ontextAidQ+."tart"Awit,U%Q--Q( value")Qpro-e tAidQ+ ! QQ if value")Qpro-e tAidQ+ [[ value")Qpro-e tAidQ+."tart"Awit,U%Q--Q( @a tion ! L tion. reate%value"( end def end an el

def delete @a tion ! L tion.find%param"):id+( @a tion.de"troy @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end end

/6 "inalmente6 nosso template RQ- que constitui a vieG delete.r%sA

page.vi"ualAeffe t :fadeJ Q ontextAa tionA?S@a tion.idTQ page.delay%5( do page.remove Q ontextAa tionA?S@a tion.idTQ end if @removeA ontext page.remove Q ontextA?S@a tion. ontext.idTQ end

?ntro u>imos um pequeno ela, na e0ecuo a remoo para que o e"eito e esaparecimento possa ro ar primeiro. ?sso completa a nossa remoo. A#ora po emos passar para a nossa e io. Para a mesma6 vamos separar a ao que "a> a e io que salva realmente os a os. (u amos inicialmente o nosso controllerA a ao

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true

**$

end def edit @a tion ! param"):id+ U L tion.find%param"):id+( : L tion.new end def "ave value" ! param"):item+.merge%S :done !. fal"e T( value")Q ontextAidQ+ ! QQ if value")Q ontextAidQ+ [[ value")Q ontextAidQ+."tart"Awit,U%Q--Q( value")Qpro-e tAidQ+ ! QQ if value")Qpro-e tAidQ+ [[ value")Qpro-e tAidQ+."tart"Awit,U%Q--Q( @a tion ! param"):id+ U L tion.update%param"):id+J value"( : L tion. reate%value"( end def end an el

def delete @a tion ! L tion.find%param"):id+( @a tion.de"troy @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end end

Depois

isso6 renomeamos a nossa vieG atualmente chama a edit.r%s para sa!e.r%s6 que termina com o

se#uinte conteP oA

if @a tion.validU page KK Qif %typeof%$%H ontextA?S@a tion. ontext.idTH(( !! HundefinedH( SQ page.in"ertA,tml :topJ Q ontext"QJ :partial !. Q ontextQJ :ob-e t !. @a tion. ontextJ :lo al" !. S :a tion" !. @a tion. ontext.a tion" T page KK QT el"e SQ if param"):id+ page.repla e Q ontextAa tionA?S@a tion.idTQJ :partial !. QitemQJ :ob-e t !. @a tion el"e page.in"ertA,tml :bottomJ Q ontextAa tion"A?S@a tion. ontext.idTQJ :partial !. QitemQJ :ob-e t !. @a tion end page KK QTQ page.vi"ualAeffe t :,ig,lig,tJ Q ontextAa tionA?S@a tion.idTQJ :duration !. 3.5 page."ortable Q ontextAa tion"A?S@a tion. ontext.idTQJ :url !. S :a tion !. QorderQJ :id !. @a tion. ontext.id T @a tion ! nil end page.repla e QeditAformQJ :partial !. QeditQ

/nquanto nossa vieG edit.r%s a#ora contJm somente issoA

page.repla e QeditAformQJ :partial !. QeditQ

Depois6 e itamos o nosso partial que #era um item6 que J o arquivo 0item.rhtmlA

Kli id!Q ontextAa tionAKY! item.id Y.Q. KY unle"" item.doneU Y. KY! ,e #AboxAtag Q ompleted)?Sitem.idT+QJ item.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. item TJ :before !. Y%1lement.",ow%Qindi atorQ((J : omplete !. Y%1lement.,ide%Qindi atorQ(((TQ Y.

**1

KY end Y. KY! item.de" ription Y. KY unle"" item.doneU Y. KY! lin#AtoAremote Q)1+QJ S :url !. S :a tion !. QeditQJ :id !. item T TJ S : la"" !. Qa tion-lin#Q T Y. KY! lin#AtoAremote Q)G+QJ S :url !. S :a tion !. QdeleteQJ :id !. item TJ : onfirm !. QLre you "ureUQ TJ S : la"" !. Qa tion-lin#Q T Y. KY end Y. Kbr. K"pan. K"trong.=ro-e t:K/"trong. KY! item.pro-e t.name Y. KY if item.doneU Y. Kbr.K"trong.4ontext:K/"trong. KY! item. ontext.name Y. Kbr.K"trong.4ompleted Lt:K/"trong. KY! item. ompletedAat."trftime%QYm/Yd/YyQ( Y. KY end Y. K/"pan. K/li.

7inalmente6 e itamos o nosso partial reponsvel pela #erao o "ormulrio e e ioA

Kdiv

la""!QeditQ id!QeditAformQ.

K,&.8ext L tionK/,&. KY! errorAme""age"Afor Qa tionQ Y. Kdiv la""!Qedit- ontent"Q.

KY formAremoteAfor :itemJ @a tionJ :url !. S :a tion !. Q"aveQJ :id !. @a tion T do MformM Y. Kp. Klabel for!QitemAde" riptionQ.Ge" ription:K/label.Kbr. KY! form.textAarea Qde" riptionQJ :row" !. 3 Y. K/p. KY if W@a tion MM @a tion.newAre ordU Y. Kp. Klabel for!QitemA ontextAidQ.4ontext:K/label.Kbr. KY! form."ele t Q ontextAidQJ 4ontext.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. Klabel for!QitemApro-e tAidQ.=ro-e t:K/label.Kbr. KY! form."ele t Qpro-e tAidQJ =ro-e t.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. KY end Y. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#AtoAremote Q4an elQJ :url !. S :a tion !. Q an elQ T Y. K/p. KY end Y. K/div. K/div.

Duan o estamos e itan o uma ao6 no queremos mu ar o seu conte0to ou pro=eto. Para isso6 bloqueamos esses campose em nosso e0emplo. +bviamente6 po erIamos querer e it;los tambJm em uma outra situao6 caso qual terIamos que

***

consi erar a possibili a e e mover itens e um local para o outro6 o que no seria muito complica o. 7a>er isso "ica como um e0ercIcio para o leitor6 consi eran o que to as as peas necessrias esto isponIveis. + resulta o e uma e io com base no c< i#o acima seriaA

-e quisermos mais uma mo i"icao A=a0 em nossa p#ina6 po erIamos acrescentar a possibili a e um usurio arraste uma ao para a lista e a&es completa as. Para isso6 precisarIamos6 inicialmente6 e mo i"icar uas

e que

e nossas vieGs. Primeiramente6 a vieG que #era

um item para acrescentar o "ato que o mesmo po e ser arrasta o.

**'

/la "icaria assimA

Kli id!Q ontextAa tionAKY! item.id Y.Q. KY unle"" item.doneU Y. KY! ,e #AboxAtag Q ompleted)?Sitem.idT+QJ item.idJ fal"eJ :on li # !. Q?SremoteAfun tion%:url !. S :a tion !. Qmar#QJ :id !. item TJ :before !. Y%1lement.",ow%Qindi atorQ((J : omplete !. Y%1lement.,ide%Qindi atorQ(((TQ Y. KY end Y. KY! item.de" ription Y. KY unle"" item.doneU Y. KY! lin#AtoAremote Q)1+QJ S :url !. S :a tion !. QeditQJ :id !. item T TJ S : la"" !. Qa tion-lin#Q T Y. KY! lin#AtoAremote Q)G+QJ S :url !. S :a tion !. QdeleteQJ :id !. item TJ : onfirm !. QLre you "ureUQ TJ S : la"" !. Qa tion-lin#Q T Y. KY end Y. Kbr. K"pan. K"trong.=ro-e t:K/"trong. KY! item.pro-e t.name Y. KY if item.doneU Y. Kbr.K"trong.4ontext:K/"trong. KY! item. ontext.name Y. Kbr.K"trong.4ompleted Lt:K/"trong. KY! item. ompletedAat."trftime%QYm/Yd/YyQ( Y. KY end Y. K/"pan. K/li. KY! draggableAelement Q ontextAa tionA?Sitem.idTQ unle"" item.doneU Y.

/m se#ui a6 mo i"icamos a nossa vieG primriaA

K,1.8ext L tion"K/,1. KY! render :partial !. QeditQ Y. Kdiv id!Q ontext"Q. KY @a tion".groupAby%[: ontext(.ea , do M ontextJ a tion"M Y. KY! render :partial !. Q ontextQJ :ob-e t !. ontextJ :lo al" !. S :a tion" !. a tion" T Y. KY end Y. K/div. Kdiv la""!QgroupQ id!Q ompletedAa tion"A ontainerQ.

K,&.4ompleted L tion"K/,&. KY! render :partial !. Qa tion"QJ :ob-e t !. @ ompletedAa tion" Y. KY! dropAre eivingAelement Q ompletedAa tion"A ontainerQJ :url !. S :a tion !. Qmar#Q T Y. K/div.

/ "inalmente6 mo i"ican o o nosso controller para receber marcar itens e acor o com a nova situaoA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+.g"ub%/)^'-6+/J QQ(( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end

**4

def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true end def edit @a tion ! param"):id+ U L tion.find%param"):id+( : L tion.new end def "ave value" ! param"):item+.merge%S :done !. fal"e T( value")Q ontextAidQ+ ! QQ if value")Q ontextAidQ+ [[ value")Q ontextAidQ+."tart"Awit,U%Q--Q( value")Qpro-e tAidQ+ ! QQ if value")Qpro-e tAidQ+ [[ value")Qpro-e tAidQ+."tart"Awit,U%Q--Q( @a tion ! param"):id+ U L tion.update%param"):id+J value"( : L tion. reate%value"( end def end an el

def delete @a tion ! L tion.find%param"):id+( @a tion.de"troy @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end end

/ssa mo i"icao J necessria por causa epois e uma operao

a maneira com os parLmetros so envia os para o controller eve ter nota o6 a or enao a lista continua

ra# an

rop. Como voc@

"uncionan o.

DEGRADAO EM AJAX
.ma coisa importante quan o li amos com A=a0 J no esabilita o. Para li ar com isso6 o Rails possui maneiras permite o uso ei0ar que tu o acontea somente por meio e #erar uma e#ra ao o Qava-cript6 = que e0istem situa&es em que um nave#a or no suporta a tecnolo#ia ou est com a mesma e "uncionali a e que e uma p#ina mesmo com o Qava-cript sem "uncionar. :oman o como e0emplo o nosso

"ormulrio e insero e a&es6 po emos "a>er um rpi o teste isso. Primeiro6 mo i"icamos o nosso partial e e ioA

Kdiv

la""!QeditQ id!QeditAformQ.

K,&.8ext L tionK/,&. KY! errorAme""age"Afor Qa tionQ Y. Kdiv TJ la""!Qedit- ontent"Q.

KY formAremoteAfor :itemJ @a tionJ :,tml !. S :a tion !. urlAfor%:a tion !. Q"aveQJ :id !. @a tion( :url !. S :a tion !. Q"aveQJ :id !. @a tion T do MformM Y.

**5

Kp. Klabel for!QitemAde" riptionQ.Ge" ription:K/label.Kbr. KY! form.textAarea Qde" riptionQJ :row" !. 3 Y. K/p. KY if W@a tion MM @a tion.newAre ordU Y. Kp. Klabel for!QitemA ontextAidQ.4ontext:K/label.Kbr. KY! form."ele t Q ontextAidQJ 4ontext.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. Kp. Klabel for!QitemApro-e tAidQ.=ro-e t:K/label.Kbr. KY! form."ele t Qpro-e tAidQJ =ro-e t.a"AdropAdownJ :prompt !. Q-- 4,oo"e --Q Y. K/p. KY end Y. Kp. KY! "ubmitAtag Q>aveQ Y. or KY! lin#AtoAremote Q4an elQJ :url !. S :a tion !. Q an elQ T Y. K/p. KY end Y. K/div. K/div.

+ parLmetro html

o mJto o form0remote0for permite especi"icarmos uma alternativa em 4:(L comum

para o "ormulrio. A#ora precisamos e uma mo i"icao em nosso controllerA

la"" ;ome4ontroller K Lppli ation4ontroller def index @a tion" ! L tion.findAbyA"tatu"%fal"e( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( end def mar# @a tion ! L tion.find%param"):id+.g"ub%/)^'-6+/J QQ(( @a tion.updateAattribute%QdoneQJ true( @ ompletedAa tion" ! L tion.findAbyA"tatu"%trueJ 3( @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end def order orderedAa tion" ! param")Q ontextAa tion"A?Sparam"):id+TQ+. olle t S MitemM item.g"ub%/)^'-6+/J QQ(.toAi T orderedAa tion".ea ,Aindex do MiM a tion ! L tion.find%orderedAa tion")i+(.updateAattribute%Qpo"itionQJ i N 1( end render :not,ing !. true end def edit @a tion ! param"):id+ U L tion.find%param"):id+( : L tion.new end def "ave value" ! param"):item+.merge%S :done !. fal"e T( value")Q ontextAidQ+ ! QQ if value")Q ontextAidQ+ [[ value")Q ontextAidQ+."tart"Awit,U%Q--Q( value")Qpro-e tAidQ+ ! QQ if value")Qpro-e tAidQ+ [[ value")Qpro-e tAidQ+."tart"Awit,U%Q--Q( @a tion ! param"):id+ U L tion.update%param"):id+J value"( :

**1

L tion. reate%value"( re"pondAto do Mwant"M want".-" want".,tml do if @a tion.validU redire tAto :a tion !. QindexQ el"e index render :a tion !. QindexQ end end end end def end an el

def delete @a tion ! L tion.find%param"):id+( @a tion.de"troy @removeA ontext ! @a tion. ontext.a tion". ount%Qdone ! 'Q( !! ' end end

+ mJto o respond0to J uma a io o Rails 1.1 que permite que uma aplicao rea=a J ei0a o como est Sprimeira linha entro

e "ormas

i"erentes

e acor o com o tipo e resposta pe i o. Bo caso acima6 se o tipo e resposta pe i o J Qava-cript6 o retorno o blocoTK se6 ao contrrio6 4:(L J pe i o6 ren eri>amos a e p#ina novamente. Com o c< i#o que = inserimos no partial e com o c< i#o = e0istente nessa ao6 o ob=eto com que estivermos trabalhan o ser salvo tranqRilamente. / isso6 com apenas um pouco mais c< i#o. Assim6 rea#ir apropria amente e acor o com a situao J possIvel. V claro que a i"icul a e varia para caso. Bo nosso e0emplo6 marcas a&es com completa as seria um pouco mais leitor. Com isso terminamos a nossa viso rpi a o A=a0 em nosso tutorial. Bo vimos tu o o que J possIvel "a>erA por e0emplo6 uploa s6 inclusive = "oi menciona o anteriormente6 so um pouco problemticos usan o A=a0. A=a0 no J uma soluo m#ica para os seus problemas para aumentar a capaci a e e "le0ibili a e quem "a> a na aus@ncia i"erena J o A=a0 est =ustamente no nosso e0emplo "inal uma aplicao. e usabili a e. V uma "erramenta muito po erosa e e se "a>er e caso e

i"Icil6 mas lon#e

impossIvel. (o i"icar to as as a&es e nossa p#ina para "uncionar sem A=a0 "ica como um e0ercIcio para o

e suas aplica&es6 mas6 como qualquer outra "erramenta6 e como "a>er com que a p#ina continue a "uncionar mesmo o que qualquer outra coisa em

esenvolve or. Pensan o nisso6 a coisa mais importante em to a a nossa parte

e Qava-cript. ?sso porque acessibili a e J mais importante

Avanando um pouco mais


Q pro#re imos bastante em nossa aplicao6 cobrin o muito o que J o ia;a; ia o esenvolvimento e um
**!

aplicao Rails. Besta seo vamos cobrir al#uns t<picos que nos permitem e0trair ain a mais "uncionali a e e nossas aplica&es. /m especial6 uma as se&es se#uintes trata e mo i"ica&es que permite um uso melhor o Rails em outros i iomas6 que provavelmente ser o seu caso6 esenvolven o aplica&es em portu#u@s6 com mensa#ens tra u>i as6 acentos e to a a para"ernlia necessria para uma aplicao locali>a a. (as6 antes e vermos isso6 vamos consi erar al#uns outros assuntosA

ROTEAMENTO AVANADO
AtJ o momento6 usamos somente o roteamento pa ro "orneci o pelo Rails6 com uma pequena e0ceo que J a p#ina inicial a aplicao6 re ireciona a anteriormente para o controller home. /m al#uns casos6 e usar .RLs especialmente con"i#ura as para a sua aplicaoHtanto por porJm6 voc@ ter necessi a e

quest&es e usabili a e e le#ibili a e como por quest&es e "acili a e e esenvolvimento. Bo arquivo routes.rb6 que vimos anteriormente6 J possIvel e"inir roteamentos i"erentes que sero

aplica os e acor o com critJrios e i enti"icao e"ini os por voc@. -uponhamos6 por e0emplo6 que queremos ver as nossas a&es separa as por com isso6 mo i"ican o o arquivo anteriormente menciona o a se#uinte "ormaA ia6 ao invJs a p#ina atual

que temos6 que simplesmente e0ibe uma lista#em. Po emos utili>ar um roteamento customi>a o para li ar

L tion4ontroller::2outing::2oute".draw do MmapM ? <,e priority i" ba"ed upon order of reation: fir"t

reated -. ,ig,e"t priority.

? >ample of regular route: ? map. onne t Qprodu t"/:idQJ : ontroller !. Q atalogQJ :a tion !. QviewQ ? Ieep in mind you an a""ign value" ot,er t,an : ontroller and :a tion ? >ample of named route: ? map.pur ,a"e Qprodu t"/:id/pur ,a"eQJ : ontroller !. Q atalogQJ :a tion !. Qpur ,a"eQ ? <,i" route an be invo#ed wit, pur ,a"eAurl%:id !. produ t.id( ? Fou an ,ave t,e root of your "ite routed by ,oo#ing up QQ ? -- -u"t remember to delete publi /index.,tml. map. onne t QQJ : ontroller !. Q,omeQ ? Lllow downloading 0eb >ervi e 0>GD a" a file wit, an exten"ion ? in"tead of a file named Qw"dlQ map. onne t Q: ontroller/"ervi e.w"dlQJ :a tion !. Qw"dlQ map. onne t Q:year/:mont,/:dayQJ : ontroller !. Qa tion"QJ :a tion !. QbyAdateQJ :re@uirement" !. S :year !. /EdS$T/J :mont, !. /EdS1J &T/J :day !. /EdS1J &T/ T ? 7n"tall t,e default route a" t,e lowe"t priority. map. onne t Q: ontroller/:a tion/:idQ end

**5

+ roteamento que estabelecemos acima in ica que esperamos tr@s itens como a composio chama os/ year6 month e day. /sses parLmetros sero passa os para a ao by0date nome J actions. + Pltimo parLmetro m@s e ia com um ou ois. A#ora po emos e"inir a nossa ao6 mo i"ican o o controller e0istenteA

e nossa .RL.

Duan o esse roteamento "or aciona o6 esses itens sero respectivamente envia os para parLmetros o controller cu=o

o roteamento in ica vali a&es que precisam ser e"etua as antes e"inimos que esperamos o ano com quatro I#itos e

que aquele roteamento se=a invoca o. Bo caso acima6

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end def byAdate @a tionApage"J @a tion" ! paginate :a tion"J : ondition" !. )Qa tion". reatedAat ! UQJ Gate.new%param"):year+.toAiJ param"):mont,+.toAiJ param"):day+.toAi(+J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ render :a tion !. Qli"tQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if re@ue"t.getU if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end el"if re@ue"t.po"tU @item ! param"):id+ U L tion.update%param"):id+J param"):item+( : L tion. reate%param"):item+( if @item.validU fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def re"our e" @a tion ! L tion.find%param"):id+( @re"our e" ! )+ if re@ue"t.po"tU [[ Wparam"):#eyword"+.blan#U @re"our e" ! 2e"our e.find%:allJ : ondition" !. )Hname li#e U or filename li#e UHJ QY?Sparam"):#eyword"+TYQJ QY?Sparam"):#eyword"+TYQ+( end end def addAre"our e" @a tion ! L tion.find%param"):id+( exi"tingAre"our eAid" ! @a tion.re"our e". olle t S Mre"our eM re"our e.id T newAre"our eAid" ! param"):re"our e"+.re-e t S MidM exi"tingAre"our eAid".in ludeU%id.toAi( T @a tion.re"our e" KK 2e"our e.find%newAre"our eAid"( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id

**2

end def deleteAre"our e @a tion ! L tion.find%param"):id+( @a tion.re"our e".delete%2e"our e.find%param"):re"our eAid+(( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end end

e""fully deletedQ

A ao cria a acima "a> uma busca basea a nos parLmetros que passamos6 como voc@ po e ver pelo resulta o abai0o Snote a .RLTA

+ uso

e roteamentos similares a esse nos permite criar .RLs que po ero ser "acilmente i enti"ica as e e permalin8s6 ou se=a6 lin8s que i enti"icam

e u>i as pelo usurio. ?sso J especialmente Ptil na criao unicamente um recurso e no mu am. /sse tipo e customi>ao J especialmente Ptil para classes

e .RL on e uma i enti"icao mais te0tual J e conteP o6 ou .RLs que

necessria como6 por e0emplos6 .RLs que

e"inem p#inas em um #erencia os


*'$

e"inem posts em um blo#. /0iste ain a uma outra classe e roteamentos que so chama os e name

routes no Rails. /sse tipo

roteamento J chama o assim porque o resulta o J uma mJto o com um nome especI"ico que po e ser invoca o e controllers e vieGs. .m e0emplo seria mo i"icar o nosso arquivo e roteamentos paraA

L tion4ontroller::2outing::2oute".draw do MmapM ? <,e priority i" ba"ed upon order of reation: fir"t

reated -. ,ig,e"t priority.

? >ample of regular route: ? map. onne t Qprodu t"/:idQJ : ontroller !. Q atalogQJ :a tion !. QviewQ ? Ieep in mind you an a""ign value" ot,er t,an : ontroller and :a tion ? >ample of named route: ? map.pur ,a"e Qprodu t"/:id/pur ,a"eQJ : ontroller !. Q atalogQJ :a tion !. Qpur ,a"eQ ? <,i" route an be invo#ed wit, pur ,a"eAurl%:id !. produ t.id( ? Fou an ,ave t,e root of your "ite routed by ,oo#ing up QQ ? -- -u"t remember to delete publi /index.,tml. map.,ome QQJ : ontroller !. Q,omeQ ? Lllow downloading 0eb >ervi e 0>GD a" a file wit, an exten"ion ? in"tead of a file named Qw"dlQ map. onne t Q: ontroller/"ervi e.w"dlQJ :a tion !. Qw"dlQ map. onne t Q:year/:mont,/:dayQJ : ontroller !. Qa tion"QJ :a tion !. QbyAdateQJ :re@uirement" !. S :year !. /EdS$T/J :day !. /EdS1J&T/J :mont, !. /EdS1J&T/ T ? 7n"tall t,e default route a" t,e lowe"t priority. map. onne t Q: ontroller/:a tion/:idQ end

Bote que6 ao invJs roteamento. Como

e usarmos o mJto o connect6 estamos

an o um nome especI"ico para o nosso escrito em controllers e vieGs por a aplicao em

ito anteriormente6 isso permite que o mesmo se=a

esse nome. Di#amos6 por e0emplo6 que queremos a#ora a icionar uma lin8 para a home nossa cabealho. Po erIamos "a>er al#o assim em nosso la,out primrioA

K,tml. K,ead. Ktitle.X<GK/title. KY! "tyle",eetAlin#Atag QdefaultQ Y. KY! "tyle",eetAlin#Atag Q" affoldQ Y. KY! -ava" riptAin ludeAtag :default" Y. K/,ead. Kbody. K,1 id!Q,eaderQ.KY! lin#Ato QX<GQJ ,omeAurl Y.K/,1. KY if "e""ionAu"er Y. Kp id!Qlogin-informationQ. Fou are logged in a" K"trong.KY! "e""ionAu"er.name Y.K/"trong.. KY! lin#Ato QDog outQJ : ontroller !. QloginQJ :a tion !. QlogoutQ Y.. K/p.

*'1

KY end Y. KY! imageAtag%Qindi ator.gifQJ :id !. Qindi atorQJ :"tyle !. Qfloat: rig,t5 margin: 5px5 di"play: noneQ( Y. Kul id!QmenuQ. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 4ontext"QJ : ontroller !. Q ontext"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 =ro-e t"QJ : ontroller !. Qpro-e t"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 L tion"QJ : ontroller !. Qa tion"QJ :a tion !. Qli"tQ Y.K/li. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 2e"our e"QJ : ontroller !. Qre"our e"QJ :a tion !. Qli"tQ Y.K/li. KY if "e""ionAu"er [[ "e""ionAu"er.adminU Y. Kli.KY! lin#AtoAunle""A urrent Q[ra@uo5 O"er"QJ : ontroller !. Qu"er"QJ :a tion !. Qli"tQ Y.K/li. KY end Y. K/ul. Kdiv id!Q ontent"Q.KY! yield Y.K/div. K/body. K/,tml.

Duan o

e"inimos uma roteamento nomea o6 o Rails automatica cria um mJto o

escreven o o mesmov

com o su"i0o 0url6 como voc@ po e ver acima. /ssa J mais uma "acili a e o"ereci a pelo "rameGor8 para "acilitar o trabalho o esenvolve or. Para completar a nossa mo i"icao6 basta inserir o se#uinte "ra#mento em nosso arquivo default.cssA

,1?,eader a S text-de oration: none5 olor: in,erit5 T

Po e no parecer muito a princIpio6 mas6 combina o isso com parLmetros6 temos al#o bastante so"istica o. )e=a o e0emplo abai0o6 mostran o um arquivo routes.rb hipotJticoA

L tion4ontroller::2outing::2oute".draw do map.wit,Aoption" : ontroller !. QblogQ blog.",ow QQJ :a tion blog.delete Qdelete/:idQJ :a tion blog.edit Qedit/:idQJ :a tion end map. onne t H: ontroller/:a tion/:view end

MmapM do MblogM !. Qli"tQ !. QdeleteQJ !. QeditQ

Com o arquivo abai0o po erIamos usar mJto os comoA

KY! lin#Ato @blog.titleJ ",owAurl Y. KY! lin#Ato @blog.titleJ deleteAurl%:id !. @blog.id( Y.

*'*

Como po emos ver6 isso realmente po e "acilitar a nossa vi a. + Pnico inconveniente J a poluio

e nosso

namespace com

e>enas

e mJto os

esse tipo. + mais interessante provavelmente J "a>er isso para

mJto os bastante usa os.

CACHING
Duan o mencionamos otimi>a&es anteriormente6 in icamos o "ato e que e0istem solu&es pr<prias no Rails para al#uns problemas comuns. .ma ve> que sua aplicao este=a termina a e voc@ tenha i enti"ica o pontos que po em se bene"iciar e a=ustes e per"ormance6 al#umas solu&es a as pelo Rails po em ser e bastante a=u a. .ma partes essas solu&es J o mecanismo e cachin# e0istente no Rails6 que permite que p#inas inteiras ou e

e p#inas se=am ren eri>a as e #uar a as como prontas para e0ibio "utura sem necessi a e

e0ecutar o c< i#o responsvel pela mesma novamente atJ que ela se=a invali a a por al#uma mu ana qualquer. + mecanismo p#ina. Apesar isso6 um os #ran es problemas e se usar cachin# em Rails J que J relativamente i"Icil acertar as op&es corretas sem testes cui a osos. /0istem tr@s tipos principais e caches no Rails e ca a um tem suas vanta#ens e esvanta#ens. A presente seo "ornece uma viso #eral e como voc@ po e usar esses mJto os sem muitas complica&es6 apontan o tambJm os problemas e ca a um. 4o=e6 com o crescimento o uso e e cachin# possui uma sJrie e "uncionali a es que permitem um bom #rau e um cache epen en o e "le0ibili a e

como6 por e0emplo6 criar vrias vers&es

os parLmetros recebi os por uma

cache em aplica&es6 plu#ins esto sur#in o para corri#ir al#uns os problemas e0istentes o Rails6 mas h
ain a al#uns problemas que e0i#em uma apro0imao mais manual. Para testar essas op&es6 vamos comear "a>en o o cache list o controller actions como e0emplo inicial. Antes e precisamos habilit;lo no mo o e uma "ra#mento e p#ina. )amos usar a ao e usarmos o mecanismo e cachin#6 porJm6

esenvolvimento6 = que ele somente J habilita o por pa ro em

pro uo. )oc@ po e mo i"icar o arquivo config/en!iroments/de!elopment.rb para issoA

? >etting" "pe ified ,ere will ta#e pre eden e over t,o"e in

onfig/environment.rb

? 7n t,e development environment your appli ationH" ode i" reloaded on ? every re@ue"t. <,i" "low" down re"pon"e time but i" perfe t for development ? "in e you donHt ,ave to re"tart t,e web"erver w,en you ma#e ode ,ange". onfig. a ,eA la""e" ! fal"e ? Dog error me""age" w,en you a onfig.w,inyAnil" ! true identally all met,od" on nil. onne t" to

? 1nable t,e brea#point "erver t,at " ript/brea#pointer onfig.brea#pointA"erver ! true

? >,ow full error report" and di"able a ,ing onfig.a tionA ontroller. on"iderAallAre@ue"t"Alo al ! true

*''

onfig.a tionA ontroller.performA a ,ing onfig.a tionAview. a ,eAtemplateAexten"ion" onfig.a tionAview.debugAr-" ? GonHt are if t,e mailer anHt "end onfig.a tionAmailer.rai"eAdeliveryAerror" ! fal"e

! true ! fal"e ! true

Reinicie o servi or para que as mo i"ica&es tenham e"eito. A#ora po emos mo i"icar a nossa vieG para ter al#um cacheA

K,1.L tion"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew L tionQJ :a tion !. QeditQ Y.K/p. KY a ,e do Y. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.Ge" riptionK/t,. Kt,.4ompletedK/t,. Kt,.0,enK/t,. Kt,.=ro-e tK/t,. Kt,.4ontextK/t,. Kt,.L tion"K/t,. K/tr. KY @a tion".ea , do Ma tionM Y. Ktr. Ktd.KY! a tion.de" ription Y.K/td. Ktd.KY! ye"AorAnoU%a tion.doneU( Y.K/td. Ktd.KY! %a tion.doneU( U a tion. ompletedAat."trftime%QYm/Yd/YyQ( : Q-Q Y.K/td. Ktd.KY! a tion.pro-e t.name Y.K/td. Ktd.KY! a tion. ontext.name Y.K/td. Ktd nowrap. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. a tion Y. orKbr. KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. a tion TJ : onfirm !. QLre you "ureUQ Y. orKbr. KY! lin#Ato Q1dit 2e"our e"QJ :a tion !. Qre"our e"QJ :id !. a tion Y. K/td. K/tr. KY end Y. K/table. KY end Y. Kp.KY! paginationAlin#"%@a tionApage"( Y.K/p.

Bo caso acima6 estamos "a>en o o cache "ra#mento.

e um "ra#mento

a p#ina. -e observamos a#ora o

iret<rio o

tmp/cache/sob nossa aplicao6 veremos que arquivos "oram cria os para conter o ren eri>ao pronta

-e a icionarmos um novo ob=eto ao banco a#ora6 veremos um "ato curiosoA ele no aparece em nossa lista#em. +utra coisa que notaremos J que6 se lo#armos como um outro usurio6 veremos as a&es primeiro. ?sso acontece porque o cache no "oi renova o no momento em que o banco so"reu mo i"ica&es. Po emos corri#ir o primeiro problema e0piran o o cache ao inserirmos6 mo i"icarmos ou e0cluirmos um o

*'4

ob=eto. .m arquivo

e cache est automaticamente associa o com o controller e ao on e "oi cria o. Por

isso6 po emos mu ar o nosso controller a se#uinte maneiraA

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end def byAdate @a tionApage"J @a tion" ! paginate :a tion"J : ondition" !. )Qa tion". reatedAat ! UQJ Gate.new%param"):year+.toAiJ param"):mont,+.toAiJ param"):day+.toAi(+J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ render :a tion !. Qli"tQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if re@ue"t.getU if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end el"if re@ue"t.po"tU @item ! param"):id+ U L tion.update%param"):id+J param"):item+( : L tion. reate%param"):item+( if @item.validU expireAfragment%:a tion !. Qli"tQ( fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def re"our e" @a tion ! L tion.find%param"):id+( @re"our e" ! )+ if re@ue"t.po"tU [[ Wparam"):#eyword"+.blan#U @re"our e" ! 2e"our e.find%:allJ : ondition" !. )Hname li#e U or filename li#e UHJ QY?Sparam"):#eyword"+TYQJ QY?Sparam"):#eyword"+TYQ+( end end def addAre"our e" @a tion ! L tion.find%param"):id+( exi"tingAre"our eAid" ! @a tion.re"our e". olle t S Mre"our eM re"our e.id T newAre"our eAid" ! param"):re"our e"+.re-e t S MidM exi"tingAre"our eAid".in ludeU%id.toAi( T @a tion.re"our e" KK 2e"our e.find%newAre"our eAid"( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def deleteAre"our e @a tion ! L tion.find%param"):id+( @a tion.re"our e".delete%2e"our e.find%param"):re"our eAid+(( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def delete L tion.find%param"):id+(.de"troy

*'5

fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ expireAfragment%:a tion !. Qli"tQ( end end

e""fully deletedQ

/ssas mo i"ica&es "oram o cache a ser renova o quan o h mu anas nos a#ora J possIvel ver que a p#ina J atuali>a6 embora persista o problema para outro usurio. Para corri#ir o problema6 precisamos e uas mu anas. Primeiro em nossa nossa vieG6 on e terIamos al#o assimA e

a os e0istentes no banco e a os incorretos aparecen o

K,1.L tion"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew L tionQJ :a tion !. QeditQ Y.K/p. KY a ,e%:a tion !. Qli"tQJ :id !. "e""ion):u"er+( do Y. Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.Ge" riptionK/t,. Kt,.4ompletedK/t,. Kt,.0,enK/t,. Kt,.=ro-e tK/t,. Kt,.4ontextK/t,. Kt,.L tion"K/t,. K/tr. KY @a tion".ea , do Ma tionM Y. Ktr. Ktd.KY! a tion.de" ription Y.K/td. Ktd.KY! ye"AorAnoU%a tion.doneU( Y.K/td. Ktd.KY! %a tion.doneU( U a tion. ompletedAat."trftime%QYm/Yd/YyQ( : Q-Q Y.K/td. Ktd.KY! a tion.pro-e t.name Y.K/td. Ktd.KY! a tion. ontext.name Y.K/td. Ktd nowrap. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. a tion Y. orKbr. KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. a tion TJ : onfirm !. QLre you "ureUQ Y. orKbr. KY! lin#Ato Q1dit 2e"our e"QJ :a tion !. Qre"our e"QJ :id !. a tion Y. K/td. K/tr. KY end Y. K/table. KY end Y. Kp.KY! paginationAlin#"%@a tionApage"( Y.K/p.

/0plicitan o o "ra#mento que estamos #ravan o em cache e in"orman o o i e nossas aplicao sem mais

o usurio lo#a o6 somos o iret<rio on e o

capa> e #erar "ra#mentos customi>a os para ca a pessoa acessan o o sistema6 aumentan o a per"ormance o que al#umas pequenas mo i"ica&es. .ma lista#em Rails #rava o cache releva o se#uinte6 epois e al#umas invoca&esA

ronaldo@minerva:~/tmp/gtd/tmp/ a ,e/lo al,o"t.3'''/a tion"/li"t$ l" -l total 8

*'1

-rw-r--r-- 1 ronaldo ronaldo 165R &''*-1'-'1 '&:'& 1. a ,e -rw-r--r-- 1 ronaldo ronaldo 1188 &''*-1'-'1 '&:'1 &. a ,e

Como po emos ver6 h um arquivo para ca a usurio no cache. A#ora precisamos mu ar a "orma como e0piramos "ra#mentos6 alteran o nosso controllerA

la"" L tion"4ontroller K Lppli ation4ontroller def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end def byAdate @a tionApage"J @a tion" ! paginate :a tion"J : ondition" !. )Qa tion". reatedAat ! UQJ Gate.new%param"):year+.toAiJ param"):mont,+.toAiJ param"):day+.toAi(+J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ render :a tion !. Qli"tQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if re@ue"t.getU if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end el"if re@ue"t.po"tU @item ! param"):id+ U L tion.update%param"):id+J param"):item+( : L tion. reate%param"):item+( if @item.validU expireAfragment%:a tion !. Qli"tQJ :id !. "e""ion):u"er+( fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def re"our e" @a tion ! L tion.find%param"):id+( @re"our e" ! )+ if re@ue"t.po"tU [[ Wparam"):#eyword"+.blan#U @re"our e" ! 2e"our e.find%:allJ : ondition" !. )Hname li#e U or filename li#e UHJ QY?Sparam"):#eyword"+TYQJ QY?Sparam"):#eyword"+TYQ+( end end def addAre"our e" @a tion ! L tion.find%param"):id+( exi"tingAre"our eAid" ! @a tion.re"our e". olle t S Mre"our eM re"our e.id T newAre"our eAid" ! param"):re"our e"+.re-e t S MidM exi"tingAre"our eAid".in ludeU%id.toAi( T @a tion.re"our e" KK 2e"our e.find%newAre"our eAid"( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def deleteAre"our e @a tion ! L tion.find%param"):id+(

*'!

@a tion.re"our e".delete%2e"our e.find%param"):re"our eAid+(( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u e""fully deletedQ redire tAto :a tion !. Qli"tQ expireAfragment%:a tion !. Qli"tQJ :id !. "e""ion):u"er+( end end

Bote que no estamos "a>en o cache

a pa#inao. + problema J similar ao que acontecia quan o e a&es

acessvamos os a os com um usurio i"erente. -e voc@ a icionar mais o que um certo nPmero chama as. A soluo J similar tambJm. Primeiro6 mo i"icamos a nossa vieGA

para que a pa#inao aparea ver que a primeira lista#em em cache ser retorna a para to as as

K,1.L tion"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew L tionQJ :a tion !. QeditQ Y.K/p. KY a ,e%:a tion !. Qli"tQJ :id !. "e""ion):u"er+J :page !. page( do Y.

Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.Ge" riptionK/t,. Kt,.4ompletedK/t,. Kt,.0,enK/t,. Kt,.=ro-e tK/t,. Kt,.4ontextK/t,. Kt,.L tion"K/t,. K/tr. KY @a tion".ea , do Ma tionM Y. Ktr. Ktd.KY! a tion.de" ription Y.K/td. Ktd.KY! ye"AorAnoU%a tion.doneU( Y.K/td. Ktd.KY! %a tion.doneU( U a tion. ompletedAat."trftime%QYm/Yd/YyQ( : Q-Q Y.K/td. Ktd.KY! a tion.pro-e t.name Y.K/td. Ktd.KY! a tion. ontext.name Y.K/td. Ktd nowrap. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. a tion Y. orKbr. KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. a tion TJ : onfirm !. QLre you "ureUQ Y. orKbr. KY! lin#Ato Q1dit 2e"our e"QJ :a tion !. Qre"our e"QJ :id !. a tion Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%@a tionApage"( Y.K/p. KY end Y.

?sso resolve a cra#a

a os

i"erentes para outras p#inas

a lista#em. -e voc@ observar o

iret<rio

cache ver o se#uinteA


*'5

ronaldo@minerva:~/tmp/gtd/tmp/ a ,e/lo al,o"t.3'''/a tion"/li"t$ l" -l total 1& -rw-r--r-- 1 ronaldo ronaldo &'R* &''*-1'-'1 1':'R 1.page!1. a ,e -rw-r--r-- 1 ronaldo ronaldo *'& &''*-1'-'1 1':'R 1.page!&. a ,e -rw-r--r-- 1 ronaldo ronaldo 1&51 &''*-1'-'1 1':'R &.page!1. a ,e

A#ora s< precisamos alterar o nosso controller para e0pirar to as as p#inas relaciona as ao usurio se houver uma mu ana e intro u>ir o mJto o page que usamosA

la"" L tion"4ontroller K Lppli ation4ontroller ,elperAmet,od :page def index li"t render :a tion !. Qli"tQ end def li"t @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end def byAdate @a tionApage"J @a tion" ! paginate :a tion"J : ondition" !. )Qa tion". reatedAat ! UQJ Gate.new%param"):year+.toAiJ param"):mont,+.toAiJ param"):day+.toAi(+J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ render :a tion !. Qli"tQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if re@ue"t.getU if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end el"if re@ue"t.po"tU @item ! param"):id+ U L tion.update%param"):id+J param"):item+( : L tion. reate%param"):item+( if @item.validU expireAfragment%/a tion"E/li"tE/?S"e""ion):u"er+T%.P(/( fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def re"our e" @a tion ! L tion.find%param"):id+( @re"our e" ! )+ if re@ue"t.po"tU [[ Wparam"):#eyword"+.blan#U @re"our e" ! 2e"our e.find%:allJ : ondition" !. )Hname li#e U or filename li#e UHJ QY?Sparam"):#eyword"+TYQJ QY?Sparam"):#eyword"+TYQ+( end end def addAre"our e" @a tion ! L tion.find%param"):id+( exi"tingAre"our eAid" ! @a tion.re"our e". olle t S Mre"our eM re"our e.id T newAre"our eAid" ! param"):re"our e"+.re-e t S MidM exi"tingAre"our eAid".in ludeU%id.toAi( T @a tion.re"our e" KK 2e"our e.find%newAre"our eAid"(

*'2

redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def deleteAre"our e @a tion ! L tion.find%param"):id+( @a tion.re"our e".delete%2e"our e.find%param"):re"our eAid+(( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u e""fully deletedQ redire tAto :a tion !. Qli"tQ expireAfragment%/a tion"E/li"tE/?S"e""ion):u"er+T%.P(/( end prote ted def page param"):page+ MM 1 end end

.samos aqui uma e0presso re#ular6 customi>a a por usurio6 para remover qualquer arquivo e cache que este=a relaciona o ao mesmo. Bo po emos usar iretamente o parLmetro page porque o mJto o expire0fragment6 quan o usa o com parLmetros livres6 opera sobre "ra#mentos especI"icos. +bviamente6 se voc@ est customi>an o o seu cache a esse ponto6 tenha certe>a e que J isso o que voc@

precisa realmente porque6 caso contrrio6 ao invJs e iminuir a car#a no servi or6 voc@ estar aumentan o a mesma6 consi eran o que o Rails passa a ter que controlar e>enas ou centenas e p#inas em cache. De uma "orma #eral6 no J interessante "a>er cache basea o em parLmetros que mu am "reqRentementeH principalmente no caso e buscasHmas a anlise eve ser "eita caso a caso. A esvanta#em e usar cache por "ra#mentos J que ele se aplica somente a vieGs. -e voc@ observar o lo# o servi or urante a ren eri>ao a ao6 ver que a chama a ao banco ain a J "eita mesmo que a p#ina = este=a em cache.

=ro e""ing L tion"4ontroller?li"t %for 1&R.'.'.1 at &''*-1'-'1 11:'':''( )X1<+ >e""ion 7G: $$*5R$ *'56de16&$ 6b &b1 bR33R$e =arameter": SQa tionQ!.Qli"tQJ Q ontrollerQ!.Qa tion"QT L tion 4ount %'.''*R&3( >1D14< 4:O8<%G7><784< a tion".id( 92:B a tion" D19< :O<12 ]:78 pro-e t" :8 pro-e t".id ! a tion".pro-e tAid D19< :O<12 ]:78 ontext" :8 ontext".id ! a tion". ontextAid 0;121 %a tion".u"erAid ! 1( L tion 4olumn" %'.''&$8&( >;:0 971DG> 92:B a tion" =ro-e t 4olumn" %'.''&1R&( >;:0 971DG> 92:B pro-e t" 4ontext 4olumn" %'.''1*3&( >;:0 971DG> 92:B ontext" L tion Doad 7n luding L""o iation" %'.''&83'( >1D14< a tion".\id\ L> t'Ar'J a tion".\de" ription\ L> t'Ar1J a tion".\done\ L> t'Ar&J a tion".\ reatedAat\ L> t'Ar3J a tion".\ ompletedAat\ L> t'Ar$J a tion".\ ontextAid\ L> t'Ar5J a tion".\pro-e tAid\ L> t'Ar*J a tion".\u"erAid\ L> t'ArRJ a tion".\po"ition\ L> t'Ar8J pro-e t".\id\ L> t1Ar'J pro-e t".\name\ L> t1Ar1J pro-e t".\de" ription\ L> t1Ar&J pro-e t".\a tive\ L> t1Ar3J pro-e t".\u"erAid\ L> t1Ar$J ontext".\id\ L> t&Ar'J ontext".\name\ L> t&Ar1J ontext".\u"erAid\ L> t&Ar& 92:B a tion" D19< :O<12 ]:78 pro-e t" :8 pro-e t".id ! a tion".pro-e tAid D19< :O<12 ]:78 ontext" :8 ontext".id ! a tion". ontextAid 0;121 %a tion".u"erAid ! 1( :2G12 /F a tion".de" ription D7B7< 'J 5 2endering wit,in layout"/appli ation 2endering a tion"/li"t 9ragment read: lo al,o"t:3'''/a tion"/li"t/1Upage!1 %'.'''&1(

*4$

O"er Doad %'.''1''3( >1D14< P 92:B u"er" 0;121 %id ! 1( D7B7< 1 O"er 4olumn" %'.''3&'8( >;:0 971DG> 92:B u"er" 4ompleted in '.'$&'8 %&3 re@"/"e ( M 2endering: '.''6&& %&1Y( M G/: '.'&''5 %$RY( M &'' :I ),ttp://lo al,o"t/a tion"/li"t+

Como J "cil perceber6 mesmo com a leitura e um "ra#mento pelo mecanismo e cachin#6 o banco e a os continua a ser acessa o. Bo e0iste uma maneira pa ro e resolver isso6 especialmente quan o estamos li an o com "ra#mentos que epen em e vrias parLmetrosHcomo J o nosso caso no momento. .ma soluo possIvel ser customi>ar a invocao ao banco e mo o que ela s< ocorra quan o necessrio6 ou se=a6 quan o o "ra#mento no "or li o. .m e0emplo isso seria "a>er as mo i"ica&es vistas em se#ui a. Primeiro6 mo i"icamos a vieG para no usar variveis e instLncia6 mas usar mJto os6 permitin o um maior controle sobre a saI aA

K,1.L tion"K/,1. KY if fla",):noti e+ Y. Kp "tyle!Q olor: green5 font-"tyle: itali Q.KY! fla",):noti e+ Y.K/p. KY end Y. Kp.KY! lin#Ato Q8ew L tionQJ :a tion !. QeditQ Y.K/p. KY a ,e%:a tion !. Qli"tQJ :id !. "e""ion):u"er+J :page !. page( do Y.

Ktable border!Q1Q ellpadding!Q5Q ell"pa ing!Q1Q. Ktr. Kt,.Ge" riptionK/t,. Kt,.4ompletedK/t,. Kt,.0,enK/t,. Kt,.=ro-e tK/t,. Kt,.4ontextK/t,. Kt,.L tion"K/t,. K/tr. KY a tion".ea , do Ma tionM Y. Ktr. Ktd.KY! a tion.de" ription Y.K/td. Ktd.KY! ye"AorAnoU%a tion.doneU( Y.K/td. Ktd.KY! %a tion.doneU( U a tion. ompletedAat."trftime%QYm/Yd/YyQ( : Q-Q Y.K/td. Ktd.KY! a tion.pro-e t.name Y.K/td. Ktd.KY! a tion. ontext.name Y.K/td. Ktd nowrap. KY! lin#Ato Q1ditQJ :a tion !. QeditQJ :id !. a tion Y. orKbr. KY! lin#Ato QGeleteQJ S :a tion !. QdeleteQJ :id !. a tion TJ : onfirm !. QLre you "ureUQ Y. orKbr. KY! lin#Ato Q1dit 2e"our e"QJ :a tion !. Qre"our e"QJ :id !. a tion Y. K/td. K/tr. KY end Y. K/table. Kp.KY! paginationAlin#"%a tionApage"( Y.K/p. KY end Y.

Depois isso6 mo i"icamos o controller para e"inir esses mJto osA

la"" L tion"4ontroller K Lppli ation4ontroller

*41

,elperAmet,od :page ,elperAmet,od :a tion"J :a tionApage" def index li"t render :a tion !. Qli"tQ end def li"t end def byAdate @a tionApage"J @a tion" ! paginate :a tion"J : ondition" !. )Qa tion". reatedAat ! UQJ Gate.new%param"):year+.toAiJ param"):mont,+.toAiJ param"):day+.toAi(+J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ render :a tion !. Qli"tQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if re@ue"t.getU if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end el"if re@ue"t.po"tU @item ! param"):id+ U L tion.update%param"):id+J param"):item+( : L tion. reate%param"):item+( if @item.validU expireAfragment%/a tion"E/li"tE/?S"e""ion):u"er+T%.P(/( fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def re"our e" @a tion ! L tion.find%param"):id+( @re"our e" ! )+ if re@ue"t.po"tU [[ Wparam"):#eyword"+.blan#U @re"our e" ! 2e"our e.find%:allJ : ondition" !. )Hname li#e U or filename li#e UHJ QY?Sparam"):#eyword"+TYQJ QY?Sparam"):#eyword"+TYQ+( end end def addAre"our e" @a tion ! L tion.find%param"):id+( exi"tingAre"our eAid" ! @a tion.re"our e". olle t S Mre"our eM re"our e.id T newAre"our eAid" ! param"):re"our e"+.re-e t S MidM exi"tingAre"our eAid".in ludeU%id.toAi( T @a tion.re"our e" KK 2e"our e.find%newAre"our eAid"( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def deleteAre"our e @a tion ! L tion.find%param"):id+( @a tion.re"our e".delete%2e"our e.find%param"):re"our eAid+(( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u e""fully deletedQ redire tAto :a tion !. Qli"tQ expireAfragment%/a tion"E/li"tE/?S"e""ion):u"er+T%.P(/( end prote ted

*4*

def a tion" loadAli"ting @a tion" end def a tionApage" loadAli"ting @a tionApage" end def loadAli"ting unle"" @a tion" @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end end def page param"):page+ MM 1 end

end

Bo c< i#o acima6 removemos as invoca&es mJto o J usa o internamente pelos outros

iretamente

a ao list

o controller. .samos ento um

mJto o6 load0listing6 que carre#a os nosso

a os somente se isso no tinha aconteci o antes. /sse e"ini os para serem os helpers a serem

ois mJto os que so

usa os na vieG. + resulta o po emos ver no lo# na pr<0ima invocao a p#inaA

=ro e""ing L tion"4ontroller?li"t %for 1&R.'.'.1 at &''*-1'-'1 18:'R:&$( )X1<+ >e""ion 7G: ead833R3$'&f$e '8ed11*16'd*55f3f =arameter": SQa tionQ!.Qli"tQJ Q ontrollerQ!.Qa tion"QJ QpageQ!.Q1QT 2endering wit,in layout"/appli ation 2endering a tion"/li"t 9ragment read: lo al,o"t:3'''/a tion"/li"t/1Upage!1 %'.'''31( O"er Doad %'.''183&( >1D14< P 92:B u"er" 0;121 %id ! 1( D7B7< 1 O"er 4olumn" %'.''$116( >;:0 971DG> 92:B u"er" 4ompleted in '.'3&'8 %31 re@"/"e ( M 2endering: '.'16'$ %56Y( M G/: '.''565 %18Y( M &'' :I ),ttp://lo al,o"t/a tion"/li"tUpage!1+

Po emos ver a#ora que as chama as ao banco para carre#ar a&es no so mais invoca as e0ceto quan o o

cache J e0pira o.
A soluo que escrevemos aqui obviamente no eve ser usa a in iscrimina amente. /la J meramente

uma escrio e uma estratJ#ia possIvel. .ma outra maneira e "a>er o cache e p#inas6 cria a para resolver o problema e acesso ao banco

acima6 J "a>er o cache

a p#ina inteira. /0istem

ois mJto os para isso no Rails6 caches0page e

caches0action. +s ois "uncionam e maneira similar6 "a>en o o cache e to a a p#ina. A i"erena J que no caso o primeiro6 caches0page6 a requisio nem passa pelo Rails uma ve> que a p#ina tenha i o para o

cache. + arquivo #era o

e cache J servi o

iretamente

o servi or. /m outros palavras6 "iltros no so

e0ecuta os6 callbac8s no ro am e assim por iante atJ que voc@ e0pire a p#ina no cache. +bviamente o comportamento e caches0page no J Ptil para a&es que
*4'

epen em

e customi>a&es em

tempo e e0ecuo basea as em parLmetros e autentica&es. (as po e ser e0tremamente Ptil para p#inas pPblicas on e o conteP o varia pouco6 especialmente quanto as mesmas so resulta o e acessos intensivos e banco. )amos e0perimentar a#ora o mJto o caches0action com uma ao que no se=a in ivi uali>a a por usurio6 como J o pr<prio ca astro e usurios. + mJto o J aplica o no pr<prio controller6 com a escrio a ao6 como po emos ver abai0oA

la"" O"er"4ontroller K Lppli ation4ontroller a ,e"Aa tion :li"t beforeAfilter :aut,enti ateAadmini"tration def index li"t render :a tion !. Qli"tQ end def li"t @u"erApage"J @u"er" ! paginate :u"er"J :perApage !. 5J :order !. QnameQ end def edit if param"):id+ @u"er ! O"er.find%param"):id+( el"e @u"er ! O"er.new end if re@ue"t.po"tU @u"er.attribute" ! param"):u"er+ "endAemail ! @u"er.newAre ordU if @u"er."ave expireAa tion%:a tion !. Qli"tQ( if "endAemail 2egi"tration8otifier.deliverAregi"trationAnotifi ation%@u"erJ "e""ionAu"er( end fla",):noti e+ ! Q<,e u"er wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def delete O"er.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e u"er wa" "u redire tAto :a tion !. Qli"tQ expireAa tion%:a tion !. Qli"tQ( end end

e""fully deletedQ

)emos tambJm que6 como em nosso e0emplo anterior6 precisamos e uma chama a para invali ar o cache. + c< i#o acima "unciona6 mas tem estamos "a>en o um cache ois problema sJrios. Primeiro6 quan o voc@ inclui6 altera ou e0clui um o arquivo em cache. ?sso acontece porque e um "ra#mento.

re#istro6 a mensa#em #era a na varivel "lash se torna parte -e#un o6 o problema com pa#inao tambJm acontece.

o conteP o completo #era o pela ao e no somente

*44

Benhum

esses

ois problemas po e ser resolvi o com mo i"ica&es M chama a

o mJto o caches0action/ e

porque o mesmo no suporta parLmetros que permitem customi>ar as chama as. /sse J um e0emplo como voc@ tem que ser cui a oso no uso e cachin# para no provocar estranhos e"eitos colaterais. (esmo assim6 h solu&es para ambos os problemas.

A questo as variveis "lash6 por e0emplo6 po eria ser resolvi o como uma mo i"icao upla6 que somente escreveremos aquiA primeiro6 movemos o c< i#o que e0ibe a mensa#em "lash para o nosso la,out6 o que po eria ser "eito sem pre=uI>o para a aplicaoK se#un o6 "a>emos uma invocao completo. /sse plu#in e uma e0plicao etalha a e como ele "uncionam6 alJm o cache atravJs e instru&es e um e uso6

plu#in chama o contentYcache que po e usa o para salvar somente o conteP o a vieG e no a p#ina por
po em ser encontra as no en ereoA httpAZZblo#.co ahale.comZ*$$1Z$4Z1$Zcontent;onl,;cachin#;"or;railsZ. .ma outra soluo para o mesmo problema seria escrever o seu pr<prio "iltro. + mJto o caches0actions J na a mais es"oro. Para o problema e pa#inao6 a soluo seria criar um roteamento especiali>a a que nos permitiria #erar a .RL customi>a a para ca a p#ina a lista#em e mo o que elas aparecessem para o cache com a&es i"erentes. 3astaria acrescentar al#o assim ao arquivo routes.rbA o que uma invocao a um "iltro aroun e voc@ po eria escrever um similar com bem pouco

L tion4ontroller::2outing::2oute".draw do MmapM ? <,e priority i" ba"ed upon order of reation: fir"t

reated -. ,ig,e"t priority.

? >ample of regular route: ? map. onne t Qprodu t"/:idQJ : ontroller !. Q atalogQJ :a tion !. QviewQ ? Ieep in mind you an a""ign value" ot,er t,an : ontroller and :a tion ? >ample of named route: ? map.pur ,a"e Qprodu t"/:id/pur ,a"eQJ : ontroller !. Q atalogQJ :a tion !. Qpur ,a"eQ ? <,i" route an be invo#ed wit, pur ,a"eAurl%:id !. produ t.id( ? Fou an ,ave t,e root of your "ite routed by ,oo#ing up QQ ? -- -u"t remember to delete publi /index.,tml. map.,ome QQJ : ontroller !. Q,omeQ ? Lllow downloading 0eb >ervi e 0>GD a" a file wit, an exten"ion ? in"tead of a file named Qw"dlQ map. onne t Q: ontroller/"ervi e.w"dlQJ :a tion !. Qw"dlQ map. onne t Q:year/:mont,/:dayQJ : ontroller !. Qa tion"QJ :a tion !. QbyAdateQJ :re@uirement" !. S :year !. /EdS$T/J :day !. /EdS1J&T/J :mont, !. /EdS1J&T/ T map. onne t Qu"er"/li"t/:pageQJ : ontroller !. Qu"er"QJ :a tion !. Qli"tQ ? 7n"tall t,e default route a" t,e lowe"t priority. map. onne t Q: ontroller/:a tion/:idQ end

+ resulta o seriam .RLs no se#uinte "ormatoA


*45

,ttp://lo al,o"t:3'''/u"er"/li"t/1 ,ttp://lo al,o"t:3'''/u"er"/li"t/& ...

Pela implementao atual

o mJto o caches0action6 ca a .RL acima #eraria seu pr<prio cache6

resolven o o problema e pa#inao6 embora no o problema as variveis "lash. .m outro inconveniente o usar cache J que precisamos controlar a e0pirao as p#inas6 um trabalho que po e "icar te ioso em pouco tempo. Para resolver o problema6 o Rails possui uma espJcie "ra#mentos e acor o com a necessi a e. )amos suport que estamos usan o a estratJ#ia ousa a para a&es em nossos outros controllers. Po eriamos criar uma classe )weeper #enJrica que nos permitisse e0pirar o cache automaticamente6 sem c< i#o e0tra no controller. Como queremos uma classe #enJrica6 vamos criar um arquivo novo no chama o list0sweeper.rbA iret<rio extras6 e classes chama as )weeper que po em ser usa a para automaticamente monitorar ob=etos e e0pirar a&es e

la"" Di"t>weeper K L tion4ontroller::4a ,ing::>weeper ob"erve =ro-e tJ 4ontextJ L tionJ 2e"our e def afterA"ave%re ord( expireAre ord%re ord( end def afterAde"troy%re ord( expireAre ord%re ord( end def expireAre ord%re ord( expireAfragment%/?Sre ord. la"".tableAnameTE/li"tE/?S"e""ion):u"er+T%.P(/( end end

+ que essa classe "a> J observar mu anas nas classes elas.

a os especi"ica as acima6 respon en o a

uas

+ mJto o obser!e6 que usamos acima6 J e"ini o na classe Cbser!er6 a qual a classe )weeper J eriva a e serve para acompanhar e "orma automtica acessos ao banco e a os "eitos por uma classe atravJs os

callbac8s que vimos anteriormente.


/m nossa classe acima6 estamos monitoran o o momento em que um ob=eto J salvo ou e0cluI o6 removen o o cache por meio o mesmo. Como o ob=eto observa o J passa o ao callbac86 temos to os seus isso que estamos usan o record.class.table0name para escobrir o a os isponIveis. V e cache iret<rio

necessrio6 consi eran o que em nossa aplicao o nome

a tabela J mapea o per"eitamente para nossos

controllers.

*41

Precisamos a#ora incluir a nova biblioteca em nosso arquivo en!ironment.rbA

? /e "ure to re"tart your web "erver w,en you modify t,i" file. ? On omment below to for e 2ail" into produ tion mode w,en ? you donHt ontrol web/app "erver and anHt "et it t,e proper way ? 18Z)H2L7D>A18ZH+ MM! Hprodu tionH ? >pe ifie" gem ver"ion of 2ail" to u"e w,en vendor/rail" i" not pre"ent 2L7D>AX1BAZ12>7:8 ! H1.1.*H ? /oot"trap t,e 2ail" environmentJ framewor#"J and default re@uire 9ile.-oin%9ile.dirname%AA97D1AA(J HbootH( onfiguration

2ail"::7nitializer.run do M onfigM ? >etting" in onfig/environment"/P ta#e pre eden e t,o"e "pe ified ,ere ? >#ip framewor#" youHre not going to u"e %only wor#" if u"ing vendor/rail"( ? onfig.framewor#" -! ) :a tionAwebA"ervi eJ :a tionAmailer + ? Ldd additional load pat," for your own u"tom dir" onfig.loadApat," N! Y0% ?S2L7D>A2::<T/extra" ( ? 9or e all environment" to u"e t,e "ame logger level ? %by default produ tion u"e" :infoJ t,e ot,er" :debug( ? onfig.logAlevel ! :debug ? O"e t,e databa"e for "e""ion" in"tead of t,e file "y"tem ? % reate t,e "e""ion table wit, Hra#e db:"e""ion": reateH( ? onfig.a tionA ontroller."e""ionA"tore ! :a tiveAre ordA"tore ? O"e >CD in"tead of L tive 2e ordH" " ,ema dumper w,en reating t,e te"t databa"e. ? <,i" i" ne e""ary if your " ,ema anHt be ompletely dumped by t,e " ,ema dumperJ ? li#e if you ,ave on"traint" or databa"e-"pe ifi olumn type" ? onfig.a tiveAre ord." ,emaAformat ! :"@l ? L tivate ob"erver" t,at ",ould alway" be running ? onfig.a tiveAre ord.ob"erver" ! : a ,erJ :garbageA olle tor ? Ba#e L tive 2e ord u"e O<4-ba"e in"tead of lo al time ? onfig.a tiveAre ord.defaultAtimezone ! :ut ? >ee 2ail"::4onfiguration for more option" end ? ? ? ? ? ? ? ? Ldd new infle tion rule" u"ing t,e following format %all t,e"e example" are a tive by default(: 7nfle tor.infle tion" do Minfle tM infle t.plural /^%ox($/iJ HE1enH infle t."ingular /^%ox(en/iJ HE1H infle t.irregular Hper"onHJ HpeopleH infle t.un ountable Yw% fi", ",eep ( end

? 7n lude your appli ation onfiguration below re@uire Qu"erAfilter.rbQ re@uire Qauditing.rbQ re@uire Qa t"Aa"AdropAdown.rbQ re@uire Qli"tA"weeper.rbQ L tionBailer::/a"e."erverA"etting" ! S :addre"" !. Qmail.yourdomain. omQJ :domain !. Qyourdomain. omQJ :u"erAname !. Qu"er@yourdomain. omQJ :pa""word !. QPPPPPPQJ :aut,enti ation !. :login

*4!

Reinicie o servi or para que as mo i"ica&es tenham e"eito. A#ora mo i"icamos o nosso controller primrio6 em application.rb6 para usar a classe acimaA

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :aut,enti ate beforeAfilter :"etA urrentAu"erAid "#ipAbeforeAfilter :aut,enti ateAadmini"trationJ :only !. ):a aroundAfilter aroundAfilter aroundAfilter aroundAfilter O"er9ilter.new%4ontextJ :neededA" ope"( O"er9ilter.new%=ro-e tJ :neededA" ope"( O"er9ilter.new%L tionJ :neededA" ope"( O"er9ilter.new%2e"our eJ :neededA" ope"( e""Adenied+

,elperAmet,od :"e""ionAu"er a ,eA"weeper :li"tA"weeperJ :only !. ) :editJ :delete + def a e""Adenied render :template !. Q",ared/a end prote ted def "etA urrentAu"erAid O"er. urrentAu"erAid ! "e""ion):u"er+ end def "e""ionAu"er @"e""ionAu"er MM! O"er.find%:fir"tJ : ondition" !. )Hid ! UHJ "e""ion):u"er++( end def aut,enti ate unle"" "e""ion):u"er+ "e""ion):returnAto+ ! re@ue"t.re@ue"tAuri redire tAto : ontroller !. QloginQJ :a tion !. QloginQ return fal"e end return true end def aut,enti ateAadmini"tration unle"" "e""ionAu"er [[ "e""ionAu"er.adminU redire tAto :a tion !. Qa e""AdeniedQ return fal"e end return true end def neededA" ope"%targetA la""( S :find !. S : ondition" !. )Q?StargetA la"".tableAnameT.u"erAid ! UQJ "e""ion):u"er++ TJ : reate !. S :u"erAid !. "e""ion):u"er+ T T end end e""AdeniedQ

A linha acima in ica que o controller eve re#istrar um sGeeper para as a&es edit e delete. Duan o essas a&es "orem e0ecuta as6 o re#istro ser mo i"ica o6
*45

isparan o a classe que re#istramos e limpan o o

cache como queremos.


)oc@ po e testar o "uncionamento usan o6 retornan o;o ao ori#inalA o c< i#o6 removen o o c< i#o e e0pirao o controller que estamos

la"" L tion"4ontroller K Lppli ation4ontroller ,elperAmet,od :page ,elperAmet,od :a tion"J :a tionApage" def index li"t render :a tion !. Qli"tQ end def li"t end def byAdate @a tionApage"J @a tion" ! paginate :a tion"J : ondition" !. )Qa tion". reatedAat ! UQJ Gate.new%param"):year+.toAiJ param"):mont,+.toAiJ param"):day+.toAi(+J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ render :a tion !. Qli"tQ end def edit @ ontext" ! 4ontext.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T @pro-e t" ! =ro-e t.find%:allJ :order !. QnameQ(. olle t S MiM )i.nameJ i.id+ T if re@ue"t.getU if param"):id+ @item ! L tion.find%param"):id+( el"e @item ! L tion.new end el"if re@ue"t.po"tU @item ! param"):id+ U L tion.update%param"):id+J param"):item+( : L tion. reate%param"):item+( if @item.validU fla",):noti e+ ! Q<,e a tion wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def re"our e" @a tion ! L tion.find%param"):id+( @re"our e" ! )+ if re@ue"t.po"tU [[ Wparam"):#eyword"+.blan#U @re"our e" ! 2e"our e.find%:allJ : ondition" !. )Hname li#e U or filename li#e UHJ QY?Sparam"):#eyword"+TYQJ QY?Sparam"):#eyword"+TYQ+( end end def addAre"our e" @a tion ! L tion.find%param"):id+( exi"tingAre"our eAid" ! @a tion.re"our e". olle t S Mre"our eM re"our e.id T newAre"our eAid" ! param"):re"our e"+.re-e t S MidM exi"tingAre"our eAid".in ludeU%id.toAi( T @a tion.re"our e" KK 2e"our e.find%newAre"our eAid"( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end def deleteAre"our e @a tion ! L tion.find%param"):id+( @a tion.re"our e".delete%2e"our e.find%param"):re"our eAid+(( redire tAto :a tion !. Qre"our e"QJ :id !. @a tion.id end

*42

def delete L tion.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e a tion wa" "u redire tAto :a tion !. Qli"tQ end prote ted def a tion" loadAli"ting @a tion" end def a tionApage" loadAli"ting @a tionApage" end

e""fully deletedQ

def loadAli"ting unle"" @a tion" @a tionApage"J @a tion" ! paginate :a tion"J :in lude !. ):pro-e tJ : ontext+J :perApage !. 5J :order !. Qa tion".de" riptionQ end end def page param"):page+ MM 1 end

end

Com isso concluImos a nossa passa#em sobre a parte muito po erosa mas que

e cachin#

o Rails6 notan o que ela realmente J esabilitar a parte e

eve ser usa a com cui a o. Caso voc@ queria6 voc@ po e

cachin# em

esenvolvimento no momento6 retornan o o arquivo config/en!ironments/de!elopment.rb/

para o se#uinteA

? >etting" "pe ified ,ere will ta#e pre eden e over t,o"e in

onfig/environment.rb

? 7n t,e development environment your appli ationH" ode i" reloaded on ? every re@ue"t. <,i" "low" down re"pon"e time but i" perfe t for development ? "in e you donHt ,ave to re"tart t,e web"erver w,en you ma#e ode ,ange". onfig. a ,eA la""e" ! fal"e ? Dog error me""age" w,en you a onfig.w,inyAnil" ! true identally all met,od" on nil. onne t" to

? 1nable t,e brea#point "erver t,at " ript/brea#pointer onfig.brea#pointA"erver ! true

? >,ow full error report" and di"able a ,ing onfig.a tionA ontroller. on"iderAallAre@ue"t"Alo al ! true onfig.a tionA ontroller.performA a ,ing ! fal"e onfig.a tionAview. a ,eAtemplateAexten"ion" ! fal"e onfig.a tionAview.debugAr-" ! true ? GonHt are if t,e mailer anHt "end onfig.a tionAmailer.rai"eAdeliveryAerror" ! fal"e

Reinicie o servi or para que as mo i"ica&es tenham e"eito.

*5$

TRADUO, UNICODE E GLOBALIZAO


AtJ o momento6 nossa aplicao "icou restrita ao i ioma in#l@s6 atJ mesmo para no termos que nos preocupar com particulari a es aplica&es em portu#u@s. Por pa ro6 o Rails no prov@ nenhuma "uncionali a e relaciona a a locali>ao e internacionali>ao. Ao contrrio6 a maioria e suas caracterIsticas e #erao automtica o i ioma in#l@s. Apesar isso6 sem #ran e es"oro6 po emos mo i"icar al#umas partes o mesmo para que possamos e al#uns e nomes J e0clusivamente volta a para o Rails. +bviamente esse provavelmente no J o seu caso6 esenvolven o

locali>ar nossas aplica&es em uma certa me i a. .ma #eralmente su"iciente para que voc@ possa usar outro i ioma. .m caso bsico J o os nomes as tabelas6 que J

essas maneiras J a re e"inicao

mJto os e constantes. Caso sua aplicao no precise "uncionar em vrios i iomas simultaneamente6 isso J

eriva o automaticamente

o nome

a classe

a os.

Caso voc@ no se sinta con"ortveis em usar nomes e mo elos em in#l@s6 pre"erin o nomes em portu#u@s6 voc@ po e "a>er al#um assimA

la"" 4ontexto K L tive2e ord::/a"e "etAtableAname Q ontexto"Q "etAprimaryA#ey Q odigoA ontextoQ end

Com essas

uas mo i"ica&es o Rails sabe que nem o nome

a tabela6 nem o nome

e sua chave primria as emais

surro#a a so os mesmos e que os nomes customi>a os "orneci os "uncionali a es automaticamente es"oro.

evem ser usa os. As mo i"ica&es se os atributos = que eles so

aplicam a qualquer chama a e no o"erecem quase nenhum problema em qualquer o Rails. Bo J necessrio se preocupar com o nome eriva os o banco e

a os. (i#ra&es tambJm aceitam mo i"ica&es sem muito

+bviamente isso no J locali>ao nem internacionali>ao no senti o bsico ser um problema. .sar o in#l@s provavelmente representa menos necessi a e aplicao6 mas no J um motivo para i"icul a es.

as palavras6 mas o c< i#o e pro#ramaoHo e e me0er aqui e ali em sua

tambJm J um ponto em que o uso e seu i iomaHcom em qualquer outra lin#ua#em

/ntretanto6 como menciona o acima6 al#uns pontos o Rails que esperam nomes em in#l@s po em comear a apresentar al#uns problemas. .m e0emplo "echa o e c< i#o maneira no c< i#o o RailsA isso J o mJto o error0messages0for6 que #erar um bloco e"ini o a se#uinte escreven o os erros #era os por um mo elo. /sse mJto o J

*51

def errorAme""age"Afor%ob-e tAnameJ option" ! ST( option" ! option"."ymbolizeA#ey" ob-e t ! in"tan eAvariableAget%Q@?Sob-e tAnameTQ( if ob-e t [[ Wob-e t.error".emptyU ontentAtag%QdivQJ ontentAtag% option"):,eaderAtag+ MM Q,&QJ Q?Spluralize%ob-e t.error". ountJ QerrorQ(T pro,ibited t,i" ?Sob-e tAname.toA".g"ub%QAQJ Q Q(T from being "avedQ ( N ontentAtag%QpQJ Q<,ere were problem" wit, t,e following field":Q( N ontentAtag%QulQJ ob-e t.error".fullAme""age". olle t S Mm"gM ontentAtag%QliQJ m"g( T(J QidQ !. option"):id+ MM Qerror1xplanationQJ Q la""Q !. option"): la""+ MM Qerror1xplanationQ ( el"e QQ end end

Bote que e0istem vrios problemas com a implementaoA primeiro6 o te0to embuti o ireto

as mensa#ens usa as est

o mJto o e no po e ser con"i#ura o. -e#un o6 o mJto o usa plurali=e para variar a

"rase que in"orma se h um ou mais erros. Como esse mJto o plurali>a bem somente palavras em in#l@s Se mesmo assim so"re e vrias e0cess&esT temos mais um ponto complica o. A soluo mais <bvia seria substituir completamente o mJto o6 usan o nossa pr<pria implementao para isso. Po erIamos6 por e0emplo6 a icionar a se#uinte implementao em nosso arquivo application0helper.rbA e helper primrip6

def errorAme""age"Afor%ob-e tAnameJ option" ! ST( option" ! option"."ymbolizeA#ey" ob-e t ! in"tan eAvariableAget%Q@?Sob-e tAnameTQ( if ob-e t [[ Wob-e t.error".emptyU ontentAtag%QdivQJ ontentAtag% option"):,eaderAtag+ MM Q,&QJ Q?Spluralize%ob-e t.error". ountJ Qerro impediuQJ Qerro" impediramQ(T @ue e""e regi"tro fo""e "alvo:Q ( N ontentAtag%QpQJ Q:" "eguinte" ampo" apre"entaram problema":Q( N ontentAtag%QulQJ ob-e t.error".fullAme""age". olle t S Mm"gM ontentAtag%QliQJ m"g( T(J QidQ !. option"):id+ MM Qerror1xplanationQJ Q la""Q !. option"): la""+ MM Qerror1xplanationQ ( el"e QQ end end

7a>en o uma vali ao qualquer6 isso resolver parcialmente o nosso problema. + cabealho in"ormao e vali ao ser corri#i o6 mas no as mensa#ens automaticamente pelo Rails. .ma "orma arquivo en!ironment.rbA e contornar isso seria re e"inir o con=unto que

e nossa escreve o

e erro por campo6 que so #era as

internamente essas mensa#ens. ?sso po eria ser "eito acrescentan o a se#uinte mo i"icao ao "inal

module L tive2e ord la"" 1rror"

*5*

@@defaultAerrorAme""age" ! S :in lu"ion !. Qnao exi"te na li"taQJ :ex lu"ion !. Q-V exi"te na li"taQJ :invalid !. Qb invVlido.QJ : onfirmation !. Qnao onfere om "ua onfirmacaoQJ :a epted !. Qdeve "er a eitoQJ :empty !. Qnao pode "er vazioQJ :blan# !. Qnao pode e"tar em bran oQJ :tooAlong !. Qb muito longo %o mVximo deve "er Yd ara tere"(QJ :tooA",ort !. Qb muito urto %o mdnimo deve "er Yd ara tere"(QJ :wrongAlengt, !. Qpo""ui o omprimento errado %o taman,o deveria "er Yd :ta#en !. Q-V foi u"ando em outro regi"troQJ :notAaAnumber !. Qnao b um nemeroQ T end end

ara tere"(QJ

+ c< i#o acima substitui a varIavel

e classe que representa as mensa#ens. -e o nome

e seus campos

estiver em portu#u@s6 isso = ser uma espJcie

e locali>ao. .m problema6 porJm6 J que as mensa#ens

"icam um pouco estranhas. )oc@ teria mensa#ens comoA

8ome nao pode "er vazio. >en,a nao onfere om "ua onfirmacao. Dogin -V foi u"ado em outro regi"tro.

+bviamente6 isso no J muito interessante. Po erIamos melhorar essas mensa#ens um pouco "a>en o uma outra mo i"icao em nosso mJto o error0messages0for6 ei0an o mesmo assimA

def errorAme""age"Afor%ob-e tAnameJ option" ! ST( option" ! option"."ymbolizeA#ey" ob-e t ! in"tan eAvariableAget%Q@?Sob-e tAnameTQ( unle"" ob-e t.error".emptyU item" ! )+ ob-e t.error".ea , S MattributeJ me""ageM item" KK ontentAtag%QliQJ me""age( T ontentAtag%QdivQJ ontentAtag% option"):,eaderAtag+ MM Q,&QJ Q?Spluralize%ob-e t.error". ountJ Qerro impediuQJ Qerro" impediramQ(T @ue e""e regi"tro fo""e "alvo:Q ( N ontentAtag%QpQJ Q:" "eguinte" ampo" apre"entaram problema":Q( N ontentAtag%QulQJ item".-oin%QQ((J QidQ !. option"):id+ MM Qerror1xplanationQJ Q la""Q !. option"): la""+ MM Qerror1xplanationQ ( end end

/ssa implementao e0ibe somente a mensa#em pura a iciona o M vali ao. Com o mJto o acima6 mo i"icarIamos um mo elo e0emplo abai0oA e a os qualquer para e0ibir mensa#ens completas na vali ao6 como no

la"" 4ontexto K L tive2e ord::/a"e "etAtableAname Q ontexto"Q "etAprimaryA#ey Q odigoA ontextoQ

*5'

validate"Apre"en eAof :nameJ :me""age !. Q: nome do ontexto deve "er informadoQ validate"Apre"en eAof :u"erAidJ :me""age !. Q: u"uVrio a""o iado ao ontexto deve "er informadoQ end

/mbora possa parecer um inconveniente e0plicitar a mensa#em

e vali ao por completo6 esse mJto o

provavelmente J o mais interessante por permitir que a mensa#em se=a cui a osamente cunha a para ca a campo e vali ao6 aumentan o bastante o #rau e le#ibili a e as mesmas. As altera&es acima provavelmente resolvem a maior parte a necessi a e e tra uo em suas aplica&es. Apesar isso6 talve> voc@ tenha um outro problema no uso ecorrem o uso e "ormatos i"erente e caracteres acentua os. /sses problemas e te0to entre as vrias partes e #eralmente e arma>enamento

sua aplicao6 passan o es e a representao interna o Rub, atJ a persist@ncia "inal no banco e a os. A soluo provavelmente mais acerta a para o problema J usar uma co i"icao comum para to os6 o que epen en er uso e al#uns "atores como o servi or e banco e a os que voc@ est usan o. Besse ponto6 o e .nico e com o "ormato .:7;5 seria provavelmente a escolha mais interessante. (as temos um

#ran e problema no "ato e que o Rub, no suporta .nico e nativamente. Apesar isso6 e0istem al#umas passos que voc@ po e tomar para que sua aplicao basicamente "ale

.nico e sem que o Rub, precise saber isso na maior parte os casos. + primeiro passo6 obviamente6 seria escolher um banco e a os que suporte .nico e com .:7;5 a verso 4.1. ?nclusive6 a partir

nativamente. + (,-DL6 por e0emplo6 somente tem suporte a isso a partir po e usar al#o assim para #erar suas tabelas com suporte a .:7;5A

a verso 5.$6 a instalao pa ro habilita o .:7;5 como co i"icao pa ro. /m vers&es anteriores6 voc@

reate table %

ontext"

id int not null autoAin rementJ foo var ,ar%1''( not nullJ primary #ey %id( ( type!myi"am ,ara ter "et utf85

/m se#ui a6 precisamos arquivo application.rbA

e um "iltro em nossa aplicao para "a>er com que o Rails retorne por pa ro na e a os. Po erIamos ter al#o assim em um

em .:7;5 e que tambJm converse em .:7;5 com o banco

la"" Lppli ation4ontroller K L tion4ontroller::/a"e beforeAfilter :"etA ,ar"et def "etA ,ar"et @re"pon"e.,eader")Q4ontent-<ypeQ+ ! Qtext/,tml5 end end ,ar"et!utf-8Q

*54

+ c< i#o acima in ica ao nave#a or que o retorno a aplicao J .:7;5. Por "im6 precisamos mu ar o nosso arquivo e con"i#urao o banco e a os para "a>er com que a

comunicao com o banco e a os tambJm se=a em .:7;5. Para o (,-DL6 a con"i#urao seria assimA

development: adapter: my"@l databa"e: db en oding: utf8 u"ername: root pa""word:

+bviamente J importante tambJm que voc@ este=a usan o um e itor que salve os seus arquivos que voc@ est #eran o em .:7;5. Caso contrrio6 o que acontecer J que qualquer te0to problemtico Sleia;se com acentosT em seus controllers6 mo els e vieGs entrar em con"lito com o "ormato #erean o p#inas que misturam aplicao "alhe. +s passos acima so capa>es caracteres as varia&es e a=u ar a resolver a maior parte os problemas com co i"icao e que nenhum e os o resto os a os6 uas ou mais co i"ica&es6 conseqRentemente "a>en o com que sua

o Rails6 mas ain a nos

ei0am com um problema "un amentalA o "ato

mJto os a classe )tring/ o Rub, suporta .nico e e que qualquer uso os mesmos em te0to que contenha e b,tes por caractere presentes no .:7;5 causar problemas. (esmo um mJto o simples como length ei0ar e "uncionar. .ma soluo quase completa para isso J usar bibliotecas para isso. Por e0emplo6 usan o o se#uinte c< i#o antes e qualquer coisa em sua aplicao Sno comeo o arquivo en!ironment.rb6 por e0emploT6 #arantir um suporte bsico ao .:7;5 no RailsA

$I4:G1 ! QuQ re@uire Q- odeQ

/sse c< i#o no cui a

e to as as "un&es

o Rub,6 mas po emos a icionar suporte para mais al#umas

usan o uma outra biblioteca. Para us;la6 primeira a instalamos via gemA

ronaldo@minerva:~/tmp/gtd$ gem in"tall uni ode /ul# updating Xem "our e index for: ,ttp://gem".rubyforge.org ... >u e""fully in"talled uni ode-'.1

Com essa biblioteca instala a6 po emos usar os mJto os abai0o no lu#ar os usuaisA

Oni ode::down a"e%"tring( Oni ode::up a"e%"tring( ? et J et J et ...

*55

?sso resolve quase to os os problemas que po erIamos ter. (as6 atJ que uma verso com suporte nativo a .nico e6 como est previsto6 no J possIvel ter 1$$b e a os entre o c< i#o e as emais partes

o Rub, se=a lana a

e con"iana que as convers&es

a aplicao "uncionam completamente. )oc@ po e ler mais

sobre o assunto emA http://wi3i.rubyonrails.com/rails/pages/.ow*oAseAnicode)trings. ?sso6 entretanto6 no tem impe i o que o Rails se=a usa o para aplica&es que no esto em in#l@s. /u venho "a>en o isso h quase escritos acima. .m Pltimo t<pico antes em termos e terminarmos essa sesso J #lobali>ao6 ou se=a6 a a aptao e uma aplicao e ois anos = e ain a no tive qualquer problema se#ui o passos similares aos

e locali>ao e internacionali>ao para que ela suporte vrios i iomas simultaneamente6

acor o com pre"er@ncias e instalao ou e usurio. Para essas tare"as6 e0istem plu#ins para o Rails que "a>em um trabalho melhor nesse tutorial tentan o qualquer coisa manualmente. Dois esses plu#ins soA %lobali>e http://plugins.radrails.org/directory/show/<N %Loc http://plugins.radrails.org/directory/show/:# )isitan o a p#ina os mesmos po e enten er mais sobre como ca a um eles "unciona e quais so suas o que po erIamos "a>er

respectivas vanta#ens e esvanta#ens.

SEGURANA
+ Rails6 por pa ro6 = "a> um bom trabalho a os em uma aplicao. /ntretanto6 o e tentar evitar os problemas mais comuns etalha al#umas icas e se#urana e esenvolve or eve estar sempre atento para no intro u>ir e se#urana que po em

problemas pr<prios em suas aplica&es. A presente seo

ser se#ui as para #arantir uma con"iabili a e maior ao seu c< i#o. .m os maiores problemas em aplica&es Eeb J a possibili a e a os em chama as ao banco e e in=eo e -DL6 que acontece quan o e "ontes inse#uras. .m

uma aplicao inclui

a os que esto vin o

e0emplo seria o c< i#o abai0oA

O"er.find :allJ : ondition" !. )Qname li#e HY?Sparam"):#eyword"TYHQ+

/sse c< i#o #era a se#uinte eclarao -DL6 ou al#o pareci o pelo menos6 para um parLmetro qualquerA

"ele t P from u"er" w,ere name li#e HYte"tYH

*51

A#ora6 ima#ine que um usurio malicioso6 ao invJs te0to como parLmetroA

e passar um palavra;chave comum6 passe o se#uinte

H5 delete P from u"er" w,ere H1!1

+ nosso c< i#o -DL seria trans"orma o6 epois a interpolao emA

"ele t P from u"er" w,ere name li#e HYte"tYH5 delete P from u"er" w,ere H1!1H

+ resulta o seria a e0cluso

e to os nossos re#istros

e usurio. Do e0emplo acima6 voc@ po e ver que

ataques bastantes so"istica os po eriam acontecer. -e o -DL construI o "or su"icientemente verstil6 um pouco e testes po er revelar inclusive etalhes e lo#ins e senhas em um banco e a os. A soluo para o problema acima J usar sempre parLmetros nomea os. A busca ori#inal "icaria assimA

O"er.find :allJ : ondition" !. )Qname li#e UQJ QY?Sparam"):#eyword"TYQ+

.san o parLmetros nomea os6 qualquer caractere potencialmente peri#oso ser trata o previamente. .ma outra prtica interessante J e0trair consultas "reqRentemente usa as para mJto os6 como "i>emos al#umas ve>es ao lon#o e nosso usurio. + mJto o acima6 por e0emplo6 po eria ser trans"orma o emA

la"" O"er K L tive2e ord::/a"e def "elf."ear ,AbyAname%#eyword"( find :allJ : ondition" !. )Qname li#e UQJ QY?S#eyword"TYQ+ end end

.m outro problema6 bem similar6 J usar parLmetros em templates RQ-6 su=eitan o a aplicao a ataques Qava-cript. Por e0emplo6 o c< i#o abai0o em uma vieG usan o RQ- J vulnervelA

KY! @param")Q#eyword"Q+ Y.

-e o c< i#o acima "or envia o em resposta a uma .RL como a abai0o6 voc@ ver um alert com o valor

os

coo8ies seta os em sua aplicao6 incluin o o session i

o usurioA

,ttp://lo al,o"t:3'''/te"t/a tionU#eyword"!Y34" riptY31alertY&8do ument. oo#ieY&6Y34Y&9" riptY31

/ssa J mais uma questo "ormulrios abertos.

e prote#er a sua aplicao

e ser rapta a por c< i#o malicioso in=eta o em

*5!

A soluo J tratar o resulta o antes6 usan o al#o comoA

KY!, @param")Q#eyword"Q+ Y.

+ mJto o h6 no Rails6 trata a sua entra a trans"orman o qualquer caractere problemtico em seu equivalente 4:(L6 prevenin o a maior partes os problemas. + c< i#o acima po e ser usa o tanto em

templates RQ- como vieGs 4:(L normais.


.m Pltimo tipo e problema J o uso e atribui&es iretas via "ormulrios6 usan o o mJto o attributes as classes e a os. -uponha que6 em nossa aplicao6 tenhamos um "ormulrio que permita que qualquer pessoa se ca astre para ser um novo usurio. + nosso c< i#o atual6 como po emos ver abai0o6 usa e0atamente esse mJto o e atribuioA

la"" O"er"4ontroller K Lppli ation4ontroller beforeAfilter :aut,enti ateAadmini"tration def index li"t render :a tion !. Qli"tQ end def li"t @u"erApage"J @u"er" ! paginate :u"er"J :perApage !. 5J :order !. QnameQ end def edit if param"):id+ @u"er ! O"er.find%param"):id+( el"e @u"er ! O"er.new end if re@ue"t.po"tU @u"er.attribute" ! param"):u"er+ "endAemail ! @u"er.newAre ordU if @u"er."ave expireAa tion%:a tion !. Qli"tQ( if "endAemail 2egi"tration8otifier.deliverAregi"trationAnotifi ation%@u"erJ "e""ionAu"er( end fla",):noti e+ ! Q<,e u"er wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end def delete O"er.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e u"er wa" "u redire tAto :a tion !. Qli"tQ expireAa tion%:a tion !. Qli"tQ( end end

e""fully deletedQ

-e usssemos o mesmo c< i#o na parte pPblica

o site Sremoven o a autenticao

a incluso

a osT6

terIamos um enorme problemaA qualquer usurio po eria se con"i#urar a ministra or

o sistema. ?sso

*55

acontece porque o atributo admin

a classe po e ser livremente atribuI o. Assim6 mesmo que no e

e0ibIssemos uma cai0a e seleo para esse atributo6 um atacante malicioso po eria simplesmente criar um p#ina que enviasse isso por ele6 evitan o tranquilamente qualquer o nosso pobre mJto o obscurecimento. A soluo J mo i"icar tanto o nosso mo elo para evitar atribui&es iretasA

la"" O"er K L tive2e ord::/a"e attrAa e""or : urrentAu"erAid eAof eAof eAof eAof :name :login :pa""word :email

validate"Apre"en validate"Apre"en validate"Apre"en validate"Apre"en

validate"Auni@uene""Aof :login attrAprote ted :admin end

Com essa mo i"icao6 nossa ao pPblica no seria mais capa> in icasse acesso a ministrativo ao banco para al#o assimA e

e atribuir automaticamente um valor que

a os. / nossa ao a ministrativa teria que ser mo i"ica a

la"" O"er"4ontroller K Lppli ation4ontroller beforeAfilter :aut,enti ateAadmini"tration def index li"t render :a tion !. Qli"tQ end def li"t @u"erApage"J @u"er" ! paginate :u"er"J :perApage !. 5J :order !. QnameQ end def edit if param"):id+ @u"er ! O"er.find%param"):id+( el"e @u"er ! O"er.new end if re@ue"t.po"tU @u"er.attribute" ! param"):u"er+ @u"er.admin ! param"):u"er+):admin+ "endAemail ! @u"er.newAre ordU if @u"er."ave expireAa tion%:a tion !. Qli"tQ( if "endAemail 2egi"tration8otifier.deliverAregi"trationAnotifi ation%@u"erJ "e""ionAu"er( end fla",):noti e+ ! Q<,e u"er wa" "u e""fully "avedQ redire tAto :a tion !. Qli"tQ end end end

*52

def delete O"er.find%param"):id+(.de"troy fla",):noti e+ ! Q<,e u"er wa" "u redire tAto :a tion !. Qli"tQ expireAa tion%:a tion !. Qli"tQ( end end

e""fully deletedQ

:o as as mo i"ica&es que vimos atJ a#ora so bem simples6 mas o uso as mesmas po e evitar incontveis problemas no esenvolvimento e uma aplicao Eeb.

UNIT TESTING
/mbora tenhamos i#nora o esse assunto mais importantes urante to o o nosso tutorial6 in iscutivelmente uma as partes e qualquer aplicao Rails so os testes que evem ser manti os sobre a mesma. .nit

testin# J uma parte "un amental a meto olo#ia /0treme Pro#rammin#6 cu=as "iloso"ias "ormam a base e
muitas ecis&es toma as no Rails. A pe ra e esquina a meto olo#ia /0treme Pro#rammin# S9PT J o teste e uni a e Sunit testT6 ou como

al#uns o chamam6 teste unitrio. .m teste6 na meto olo#ia 9P J uma as maneiras e saber se o c< i#o que "oi escrito se con"orma aos requerimentos posteriormente M criao Por causa o mesmo e6 mais ain a6 se mu anas intro u>i as esenvolvimento a partir os o mesmo no invali aram c< i#o = e0istente6 intro u>in o bu#s na aplicao.

isso6 aplica&es se#uin o a meto olo#ia 9P sempre comeam o

testes6 e"inin o as con i&es se#un o as quais o c< i#o a ser esenvolvi o eve ser cria o. + racional para isso J o "ato simples e que6 se um teste ra>oavelmente completo passa6 o c< i#o escrito provavelmente est correto. + ob=etivo esse tutorial no J o"erecer uma intro uo M meto olo#ia 9P6 mas mostrar6 pelo menos o esviar a nossa ateno

inicialmente6 como a mesma po e ser aplica a ao Rails no que concerne a testes. Para prop<sitos tutorial6 os testes "oram i#nora os atJ o momento porque intro u>i;los si#ni"icaria a emonstrao o Rails em si. -e voc@ recomen a osA http://en.wi3ipedia.org/wi3i/Anit0testing http://en.wi3ipedia.org/wi3i/*est'dri!en0de!elopment http://c;.com/cgi/wi3i?*estLri!enLe!elopment http://www.xprogramming.com/testfram.htm + Rails o"erecia6 atJ a verso 1.16 uas "ormas principais e testesA testes e

ese=a apren er mais sobre 9P e testes6 abai0o esto al#uns lin8s

e uni a e6 = menciona os

acima6 e testes "uncionais. +s primeiros testam os mo elos

a os6 #arantin o que vali a&es6

associa&es e quaisquer outros a en os ao bsico "uncionam correstamente. +s Pltimos testam se a "uncionali a e bsica a aplicao6 como presente em controllers e vieGs6 est correta. .m novo tipo e testes "oi intro u>i o com o Rails 1.16 que so os testes
*1$

e inte#rao. /sses testes so

responsveis por veri"icar o "uncionamento testes "uncionais outras palavras6 os testes

e partes conecta as e

e uma aplicao. -o uma e0panso os testes

os

a mesma "orma que os testes "uncionais so uma e0tenso e uni a e veri"icam se as classes

e uni a e. /m e inte#rao uas Pltimas

a os esto "uncionan o corretamenteK os

testes "uncionais veri"icam se o uso

a mesmas est correto nos controllersK e os testes

veri"icam se as inter epen @ncias entre as mesmas tambJm esto corretasHsen o que estas veri"ica&es so "eitas sobre controllers e vieGs tambJm.

Para "a>er uso e testes6 o Rails utili>a a biblioteca test/unit6 que vem por pa ro com o Rub,. A biblioteca J transparentemente incluI a no Rails e utili>a a tambJm e maneira bem transparente. A maioria os coman os e #erao que vimos atJ o momento cria automaticamente testes para ca a pea intro u>i a na aplicao. Para testar completamente uma aplicao em Rails6 usamos o coman o abai0oA

ra#e te"t

+ resulta o o coman o abai0o6 na aplicao que temos a#ora6 J al#o assimA

ronaldo@minerva:~/tmp/gtd$ ra#e te"t %in /,ome/ronaldo/tmp/gtd( /u"r/bin/ruby1.8 -7lib:te"t Q/u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader.rbQ Qte"t/unit/pro-e tAte"t.rbQ Qte"t/unit/a tionAte"t.rbQ Qte"t/unit/ ontextAte"t.rbQ Qte"t/unit/u"erAte"t.rbQ Qte"t/unit/re"our eAte"t.rbQ Qte"t/unit/regi"trationAnotifierAte"t.rbQ Qte"t/unit/auditAte"t.rbQ Doaded "uite /u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader >tarted ....... 9ini",ed in '.1'*8R3 "e ond". R te"t"J R a""ertion"J ' failure"J ' error" /u"r/bin/ruby1.8 -7lib:te"t Q/u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader.rbQ Qte"t/fun tional/,omeA ontrollerAte"t.rbQ Qte"t/fun tional/ ontext"A ontrollerAte"t.rbQ Qte"t/fun tional/pro-e t"A ontrollerAte"t.rbQ Qte"t/fun tional/a tion"A ontrollerAte"t.rbQ Qte"t/fun tional/loginA ontrollerAte"t.rbQ Qte"t/fun tional/re"our e"A ontrollerAte"t.rbQ Qte"t/fun tional/u"er"A ontrollerAte"t.rbQ Qte"t/fun tional/feedA ontrollerAte"t.rbQ Doaded "uite /u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader >tarted ........ 9ini",ed in '.'&81R "e ond". 8 te"t"J 8 a""ertion"J ' failure"J ' error" /u"r/bin/ruby1.8 -7lib:te"t Q/u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader.rbQ Doaded "uite /u"r/bin/ra#e >tarted 9ini",ed in '.'''3'8 "e ond". ' te"t"J ' a""ertion"J ' failure"J ' error"

+ coman o acima ro a tanto os testes

e uni a e com os testes "uncionais

a aplicao. Caso

ese=emos6

po emos test;los separa amente6 como mostra o abai0oA

ronaldo@minerva:~/tmp/gtd$ ra#e te"t:unit" %in /,ome/ronaldo/tmp/gtd( /u"r/bin/ruby1.8 -7lib:te"t Q/u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader.rbQ

*11

Qte"t/unit/pro-e tAte"t.rbQ Qte"t/unit/a tionAte"t.rbQ Qte"t/unit/ ontextAte"t.rbQ Qte"t/unit/u"erAte"t.rbQ Qte"t/unit/re"our eAte"t.rbQ Qte"t/unit/regi"trationAnotifierAte"t.rbQ Qte"t/unit/auditAte"t.rbQ Doaded "uite /u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader >tarted ....... 9ini",ed in '.&*16$R "e ond". R te"t"J R a""ertion"J ' failure"J ' error" Doaded "uite /u"r/bin/ra#e >tarted 9ini",ed in '.'''31* "e ond". ' te"t"J ' a""ertion"J ' failure"J ' error" ronaldo@minerva:~/tmp/gtd$ ra#e te"t:fun tional" %in /,ome/ronaldo/tmp/gtd( /u"r/bin/ruby1.8 -7lib:te"t Q/u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader.rbQ Qte"t/fun tional/,omeA ontrollerAte"t.rbQ Qte"t/fun tional/ ontext"A ontrollerAte"t.rbQ Qte"t/fun tional/pro-e t"A ontrollerAte"t.rbQ Qte"t/fun tional/a tion"A ontrollerAte"t.rbQ Qte"t/fun tional/loginA ontrollerAte"t.rbQ Qte"t/fun tional/re"our e"A ontrollerAte"t.rbQ Qte"t/fun tional/u"er"A ontrollerAte"t.rbQ Qte"t/fun tional/feedA ontrollerAte"t.rbQ Doaded "uite /u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader >tarted ........ 9ini",ed in '.'$5*81 "e ond". 8 te"t"J 8 a""ertion"J ' failure"J ' error" Doaded "uite /u"r/bin/ra#e >tarted 9ini",ed in '.'''331 "e ond". ' te"t"J ' a""ertion"J ' failure"J ' error"

Como po emos ver pelos coman os usa os6 o que essa tare"a test/unit para ro ar ca a um que um mero teste retornan o ver a eiro. .m arquivo e caso e testes6 se=a "uncional ou a hierarquia e testes se#ue o se#uinte "ormatoA

o ra3e "a> J meramente invocar a biblitoeca o

os testes = cria os atJ o momento6 que passam por no conterem mais

e uni a e6 po e conter vrios testes entro e si. De "ato6

:o os os arquivos e teste e uma aplicao "orma uma suite e testesK .ma suite e testes possui muitos casos e testeK .m caso e testes possui muitos testesK .m teste possui muitas asser&es. i>6 so a"irma&es sobre a vali a e e uma etermina a parte o e

As asser&es6 com o pr<prio nome

c< i#o. .ma assero po eria6 por e0emplo6 vrias asser&es relaciona as.

i>er se ao atribuirmos o valor ver a eiro ao atributo done

nossa classe -ction6 o valor o atributo completed J con"i#ura o para uma

ata. .m teste qualquer possui

Bo Rails6 J aqui que entra o banco e testes que con"i#uramos em nosso aplicao. Ao ro armos o suite testes a aplicao6 esse banco J estruI o e recria o limpo para que os testes possam operar em

a os

con"iveis e "uncionar corretamente. + banco e0iste para =ustamente no termos que nos preocupar com os
*1*

ambientes

e pro uo e

esenvolvimento6

ei0an o;os intoca osHprincipalmente para o caso em que

estivermos "a>en o testes que envolvem a remoo e a os. -e voc@ observar o po er usarA iret<rio test que se encontra em sua aplicao6 ver uma sJrie e iret<rios que voc@

ronaldo@minerva:~/tmp/gtd/te"t$ l" -l total &8 drwxr-xr-x 3 ronaldo ronaldo $'6* &''*-'6-&$ drwxr-xr-x & ronaldo ronaldo $'6* &''*-'6-&$ drwxr-xr-x & ronaldo ronaldo $'6* &''*-'6-&& drwxr-xr-x $ ronaldo ronaldo $'6* &''*-'6-&& -rw-r--r-- 1 ronaldo ronaldo 131R &''*-'6-&& drwxr-xr-x 3 ronaldo ronaldo $'6* &''*-'6-&$ drwxr-xr-x & ronaldo ronaldo $'6* &''*-1'-'1

&&:5$ 1R:35 &3:1R &3:1R &3:1R 16:&& &3:31

fixture" fun tional integration mo #" te"tA,elper.rb tmp unit

/ itaremos =ustamente arquivos nesses iret<rios para reali>ar os testes que precisamos. Dois os iret<rios acima so e particular interesse. Para testarmos se a "uncionali a e relativa aos e a os para isso. + iret<rio fixtures contJm =ustamente e a os para testes urante a a a os a serem carre#a os no banco

mo elos est correta6 J <bvio que pecisamos arquivos que nos permitem in"ormar e0ecuo os mesmos. Q o

iret<rio moc3s po e eventualmente conter classes que simulam aspectos

aplicao no isponIveis urante testesHum e0emplo seria "uncionali a e que epen e e servios e re e que no po em ser usa os para homolo#ao. Q "alamos bastante sobre a teoria por trs os testes no Rails. )amos colocar isso em prtica crian o nossos primeiros testes e uni a e. Para comear6 vamos carre#ar al#uns iret<rio6 vemos uma sJrie a os em nosso banco usan o al#umas "i0tures. Dentro esse

e arquivos .,ml correspon en o aos nosso mo elos. / itaremos o arquivo

relativo a usurios que6 no momento6 contJm o se#uinteA

fir"t: id: 1 anot,er: id: &

)amos mo i"icar o arquivo para al#o assimA

ronaldo: id: 1 name: 2onaldo login: ronaldo pa""word: te"t admin: true email: ronaldo@refle tive"urfa e. om mar u": id: & name: Bar u"

*1'

login: mar u" pa""word: te"t admin: fal"e email: mar u"@refle tive"urfa e. om

+s

a os que acabamos

e intro u>ir sero automaticamente inseri os em nosso banco

e testes quan o

precisarmos os mesmos. A#ora que temos al#uns a os6 vamos testar a "uncionali a e presente em nossos mo elos. Para isto6 vamos e itar o arquivo user0test.rb6 que est no iret<rio unit. /sse arquivo est e"ini o assim no momentoA

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH la"" O"er<e"t K <e"t::Onit::<e"t4a"e fixture" :u"er" ? 2epla e t,i" wit, your real te"t". def te"tAtrut, a""ert true end end

Como po emos ver6 esse arquivo e"ine uma classe Aser*est que J um caso e teste6 como evi encia o pelo classe a qual J eriva a. /sse caso e teste contJm um Pnico teste no momento6 que simplesmente passa por testar al#o que sempre ser ver a eiro. )e=a que o arquivo = carre#a as "i0tures necessrias para o mesmo. V nesse momento que nossos a os e teste so carre#a os o banco. -e quisermos6 po emos carre#ar outras "i0tures simplesmente eclaran o;as com o mesmo coman o. + sImbolo passa o para a "uno representa o arquivo no iret<rio fixtures. B<s usamos esses arquivos e"inin o mJto os que representam testes. )amos comear com o bsico6

testan o se nossos a os po em ser recupera os o banco sem problemasA (o i"icamos o nosso arquivo e teste para o se#uinteA

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH la"" O"er<e"t K <e"t::Onit::<e"t4a"e fixture" :u"er" def te"tAba"i A"ele tion" a""ertAe@ual Q2onaldoQJ u"er"%:ronaldo(.name a""ertAe@ual QBar u"QJ u"er"%:mar u"(.name a""ertAe@ual &J O"er. ount end end

Como po emos ver6 removemos o teste anterior e criamos o nosso pr<prio teste. + primeiro teste usa a
*14

assero assert0equal para comparar ois valores. Ba primeira as asser&es acima6 veri"icamos se temos realmente ois usurios no banco. Como eclaramos ois usurios em nossas "i0tures6 esse teste everia retornar corretamente. A se#un a e a terceira assero recuperam que usamos para ois usurios o banco e veri"icam se os seus nomes a os o banco. +s sImbolos

correspon em ao que esperamos. Bote a construo usa a para recuperar os eclarar nossos usurios no arquivo mesmos a os o banco e a os6 por atribuio. Ro an o os testes6 veremos se eles passamA

e "i0tures po em ser usa os para recuperar esses

ronaldo@minerva:~/tmp/gtd$ ra#e te"t:unit" %in /,ome/ronaldo/tmp/gtd( /u"r/bin/ruby1.8 -7lib:te"t Q/u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader.rbQ Qte"t/unit/pro-e tAte"t.rbQ Qte"t/unit/a tionAte"t.rbQ Qte"t/unit/ ontextAte"t.rbQ Qte"t/unit/u"erAte"t.rbQ Qte"t/unit/re"our eAte"t.rbQ Qte"t/unit/regi"trationAnotifierAte"t.rbQ Qte"t/unit/auditAte"t.rbQ Doaded "uite /u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader >tarted ....... 9ini",ed in '.3'55*$ "e ond". R te"t"J 6 a""ertion"J ' failure"J ' error" Doaded "uite /u"r/bin/ra#e >tarted 9ini",ed in '.'''3'6 "e ond". ' te"t"J ' a""ertion"J ' failure"J ' error"

)emos que nos sete testes que temos6 com suas nove asser&es6 to as passam. .ma maneira mais "cil veri"icar se os testes especI"icos que estamos construin o esto passan o J invocar e testes6 como no e0emplo abai0oA

iretamente o arquivo

ronaldo@minerva:~/tmp/gtd$ ruby te"t/unit/u"erAte"t.rb Doaded "uite te"t/unit/u"erAte"t >tarted . 9ini",ed in '.'*$1$R "e ond". 1 te"t"J 3 a""ertion"J ' failure"J ' error"

Ca a arquivo e testes J auto;conti o e po e ser testa o corretamente. Como esperamos6 temos um teste e tr@s asser&es que passam sem problemas. )amos i>er que precisamos e mais um usurio. Para isso mo i"icamos o nosso arquivo e "i0turesA

ronaldo: id: 1 name: 2onaldo

*15

login: ronaldo pa""word: te"t admin: true email: ronaldo@refle tive"urfa e. om mar u": id: & name: Bar u" login: mar u" pa""word: te"t admin: fal"e email: mar u"@refle tive"urfa e. om ale""andra: id: 3 name: Lle""andra login: ale""andra pa""word: te"t admin: fal"e email: ale""andra@refle tive"urfa e. om

-e ro armos o nosso teste a#ora6 veremos o se#uinteA

ronaldo@minerva:~/tmp/gtd$ ruby te"t/unit/u"erAte"t.rb Doaded "uite te"t/unit/u"erAte"t >tarted 9 9ini",ed in '.&85&83 "e ond". 1( 9ailure: te"tAba"i A"ele tion"%O"er<e"t( )te"t/unit/u"erAte"t.rb:6+: K&. expe ted but wa" K3.. 1 te"t"J 3 a""ertion"J 1 failure"J ' error"

)amos a#ora que6

os tr@s testes que estabelecemos6 um "alhou. ?sso J enota o no s< pela lista#em #eral

no "im o teste comotambJm pela linha que comea com uma letra 7 maiPscula S"ailureT. + teste nos in"orma tambJm o que "alhou6 para que possamos corri#i;lo. Bo caso aqui6 vamos corri#ir o nosso teste6 = que a "alha est no mesmo. /m testes elabora os corretamente6 porJm6 basicamente qualquer problema seria corri#i o no c< i#oHa menos que o teste realmente contenha um bu#. + nosso teste a#ora seriaA

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH la"" O"er<e"t K <e"t::Onit::<e"t4a"e fixture" :u"er" def te"tAba"i A"ele tion" a""ertAe@ual Q2onaldoQJ u"er"%:ronaldo(.name a""ertAe@ual QBar u"QJ u"er"%:mar u"(.name a""ertAe@ual 3J O"er. ount end end

/ passaria sem problemas.


*11

.ma coisa a se manter em mente J que a primeira assero a "alhar em um teste invali a to o o teste. ?sso se =usti"ica pelo "ato e que um teste J uma uni a e6 que eve representar um con=unto completo e asser&es sobre o que se quer testar e mo o que na aHatJ on e J humanamente possIvelH"ique e "ora. Di#amos a#ora que queremos esten er os nossos testes para testar opera&es bsicas em nosso mo elo a os. e

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH la"" O"er<e"t K <e"t::Onit::<e"t4a"e fixture" :u"er" def te"tAba"i A"ele tion" a""ertAe@ual Q2onaldoQJ u"er"%:ronaldo(.name a""ertAe@ual QBar u"QJ u"er"%:mar u"(.name a""ertAe@ual 3J O"er. ount end def te"tA rud u"er ! O"er.new%:name !. Q2enatoQ( a""ert u"er."ave end end

Ro an o esse teste6 temos uma "alha6 obviamente6 = que s< in"ormarmos o nome al#umas vali a&es que impe em que o usurio se=a salvo sem a os.

o usurio e temos

ronaldo@minerva:~/tmp/gtd$ ruby te"t/unit/u"erAte"t.rb Doaded "uite te"t/unit/u"erAte"t >tarted .9 9ini",ed in '.&61*5$ "e ond". 1( 9ailure: te"tA rud%O"er<e"t( )te"t/unit/u"erAte"t.rb:1$+: Kfal"e. i" not true. & te"t"J $ a""ertion"J 1 failure"J ' error"

)e=a que a#ora temos ois testes6 com quatro asser&es6 as quais uma est "alhan o. A linha lo#o abai0o a "rase N-tarte O se#un o no. +bviamente6 como estamos crian o os nossos testes epois e = termos construI o a aplicao6 os mesmos no "a>em muito senti o. DaI a necessi a e e testarmos antes e construir a aplicao6 plane=an o em testes a "uncionali a e que ese=amos antes mesmo que ela este=a l. A i Jia por trs o 9P no J mo i"icar testes para que eles passem6 mas mo i"icar c< i#o para que ele satis"aa aos testes estabeleci os6 consi eran o que este=am corretos. -e montarmos os nossos testes antes e qualquer coisa6 to a a nossa uma representao NvisualO e nossos testes mostran o que o primeiro passou6 mas o

*1!

pro uo

e c< i#o se resumir M criao

e c< i#o para implementar a "uncionali a e que =

estabelecemos. .m teste um pouco mais so"istica o6 que po erIamos ter elabora o no comeo ter si o assimA e nossa aplicao po eria

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH la"" O"er<e"t K <e"t::Onit::<e"t4a"e fixture" :u"er" def te"tAba"i A"ele tion" a""ertAe@ual Q2onaldoQJ u"er"%:ronaldo(.name a""ertAe@ual QBar u"QJ u"er"%:mar u"(.name a""ertAe@ual 3J O"er. ount end def te"tA rud u"er ! O"er.new%:name !. Q2enatoQJ :login !. QrenatoQJ :pa""word !. QrenatoQJ :email !. Qrenato@refle tive"urfa e. omQ( a""ert u"er."ave a""ertAe@ual $J O"er. ount a""ert Wu"er.adminU u"er.pa""word ! Qte"tQ a""ert u"er."ave "ameAu"er ! O"er.find%u"er.id( a""ertAe@ual u"er.nameJ "ameAu"er.name differentAu"er ! O"er.find%1( a""ertAnotAe@ual u"er.idJ differentAu"er.id a""ertAnotAe@ual u"er.nameJ differentAu"er.name a""ert u"er.de"troy a""ertAe@ual 3J O"er. ount end end

)e=a que estamos testan o basicamente to as as opera&es bsicas para um ob=eto nosso teste a#ora6 temosA

e a os. /0ecutan o o

ronaldo@minerva:~/tmp/gtd$ ruby te"t/unit/u"erAte"t.rb Doaded "uite te"t/unit/u"erAte"t >tarted .. 9ini",ed in '.13*3$3 "e ond". & te"t"J 1& a""ertion"J ' failure"J ' error"

Para e0perimentar com a criao e "uncionali a e que no temos no momento6 vamos supor que queremos a icionar uma relacionamento entre usurios e a&es. Como no temos isso em nosso mo elo no momento6 po emos comear e maneira simplesA

*15

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH la"" O"er<e"t K <e"t::Onit::<e"t4a"e fixture" :u"er" def te"tAba"i A"ele tion" a""ertAe@ual Q2onaldoQJ u"er"%:ronaldo(.name a""ertAe@ual QBar u"QJ u"er"%:mar u"(.name a""ertAe@ual 3J O"er. ount end def te"tA rud u"er ! O"er.new%:name !. Q2enatoQJ :login !. QrenatoQJ :pa""word !. QrenatoQJ :email !. Qrenato@refle tive"urfa e. omQ( a""ert u"er."ave a""ertAe@ual $J O"er. ount a""ert Wu"er.adminU u"er.pa""word ! Qte"tQ a""ert u"er."ave "ameAu"er ! O"er.find%u"er.id( a""ertAe@ual u"er.nameJ "ameAu"er.name differentAu"er ! O"er.find%1( a""ertAnotAe@ual u"er.idJ differentAu"er.id a""ertAnotAe@ual u"er.nameJ differentAu"er.name a""ert u"er.de"troy a""ertAe@ual 3J O"er. ount end def te"tAa tion"Arelation",ip u"er ! u"er"%:ronaldo( a""ertAre"pondAto u"erJ :a tion" a""ertAe@ual 'J u"er.a tion"."ize end end

/m nosso novo teste6 veri"icamos se a classe respon e a um mJto o actions6 que representaria o nosso relacionamento e6 em se#ui a6 se o tamanho que esperamos para o con=unto e a&es e um usurio J va>io. + resulta o o teste JA

ronaldo@minerva:~/tmp/gtd$ ruby te"t/unit/u"erAte"t.rb Doaded "uite te"t/unit/u"erAte"t >tarted 9.. 9ini",ed in '.315*& "e ond". 1( 9ailure: te"tAa tion"Arelation",ip%O"er<e"t( )te"t/unit/u"erAte"t.rb:$1+: K?KO"er:'xbRR5&e$' @attribute"! SQnameQ!.Q2onaldoQJ QadminQ!.Q1QJ QidQ!.Q1QJ

*12

Qpa""wordQ!.Qte"tQJ QloginQ!.QronaldoQJ QemailQ!.Qronaldo@refle tive"urfa e. omQT.. of type KO"er. expe ted to re"pondAtoUK:a tion".. 3 te"t"J 13 a""ertion"J 1 failure"J ' error"

Como espera o6 temos uma "alha. ?mplementamos a nossa "uncionali a e a#ora com o se#uinte c< i#oA

la"" O"er K L tive2e ord::/a"e attrAa e""or : urrentAu"erAid eAof eAof eAof eAof :name :login :pa""word :email

validate"Apre"en validate"Apre"en validate"Apre"en validate"Apre"en

validate"Auni@uene""Aof :login ,a"Amany :a tion" end

/ nosso teste passa sem problemasA

ronaldo@minerva:~/tmp/gtd$ ruby te"t/unit/u"erAte"t.rb Doaded "uite te"t/unit/u"erAte"t >tarted ... 9ini",ed in '.&R3$8 "e ond". 3 te"t"J 1$ a""ertion"J ' failure"J ' error"

/ssa J uma "uncionali a e muito simples

e testar6 mas po erIamos ter a iciona o c< i#o

e teste que

veri"icasse se o relacionamento "unciona como queremos. Po erIamos nos alon#ar mais6 mas a i Jia = est passa a. /stes so os testes a#ora como so os testes "uncionais. )amos trabalhar com o mesmo mo elo e a os6 usan o o controller responsvel pelo mesmo. + arquivo6 chama o apropria amente users0controller0test.rb6 est no iret<rio functional e contJm o se#uinte6 no momentoA e uni a e e po emos ver

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH re@uire Hu"er"A ontrollerH ? 2e-rai"e error" aug,t by t,e ontroller. la"" O"er"4ontroller5 def re" ueAa tion%e( rai"e e end5 end la"" O"er"4ontroller<e"t K <e"t::Onit::<e"t4a"e

*!$

def "etup @ ontroller ! O"er"4ontroller.new @re@ue"t ! L tion4ontroller::<e"t2e@ue"t.new @re"pon"e ! L tion4ontroller::<e"t2e"pon"e.new end ? 2epla e t,i" wit, your real te"t". def te"tAtrut, a""ert true end end

)e=a que a i Jia J a mesma6 com a i"erena que temos a#ora um mJto o setup6 que J responsvel por criar as con i&es necessrias para nosso teste. .m mJto o oposto6 chama a teardown6 e0iste para principalmente quan o h recursos "Isicos associa os e os mesmos posteriores. )amos testar a#ora al#uns pontos em nosso controllerA escarre#ar o que criamos em setup6 o que #eralmente J necessrio somente para ob=etos com epen @ncias comple0as6 evem ser reiniciali>a os para testes

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH re@uire Hu"er"A ontrollerH ? 2e-rai"e error" aug,t by t,e ontroller. la"" O"er"4ontroller5 def re" ueAa tion%e( rai"e e end5 end la"" O"er"4ontroller<e"t K <e"t::Onit::<e"t4a"e def "etup @ ontroller ! O"er"4ontroller.new @re@ue"t ! L tion4ontroller::<e"t2e@ue"t.new @re"pon"e ! L tion4ontroller::<e"t2e"pon"e.new end def te"tAindex get :index a""ertAre"pon"e :"u end end

e""

Ro an o o nosso teste6 temosA

ronaldo@minerva:~/tmp/gtd$ ruby te"t/fun tional/u"er"A ontrollerAte"t.rb Doaded "uite te"t/fun tional/u"er"A ontrollerAte"t >tarted 9 9ini",ed in '.'5536* "e ond". 1( 9ailure: te"tAindex%O"er"4ontroller<e"t( )te"t/fun tional/u"er"A ontrollerAte"t.rb:1*+: 1xpe ted re"pon"e to be a K:"u e"".J but wa" K3'&. 1 te"t"J 1 a""ertion"J 1 failure"J ' error"

.ma "alha <bvia = que a nossa ao e0pera um lo#in. .m teste mais completo seriaA

*!1

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH re@uire Hu"er"A ontrollerH ? 2e-rai"e error" aug,t by t,e ontroller. la"" O"er"4ontroller5 def re" ueAa tion%e( rai"e e end5 end la"" O"er"4ontroller<e"t K <e"t::Onit::<e"t4a"e fixture" :u"er" def "etup @ ontroller ! O"er"4ontroller.new @re@ue"t ! L tion4ontroller::<e"t2e@ue"t.new @re"pon"e ! L tion4ontroller::<e"t2e"pon"e.new end def te"tAindex get :index a""ertAredire tedAto : ontroller !. QloginQJ :a tion !. QloginQ end def te"tAindexAwit,Alogin @re@ue"t."e""ion):u"er+ ! u"er%:ronaldo(.id get :index a""ertAre"pon"e :"u e"" end end

-e quisermos "a>er al#o ain a mais completo6 po emos testar o que e0iste na respostaA

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH re@uire Hu"er"A ontrollerH ? 2e-rai"e error" aug,t by t,e ontroller. la"" O"er"4ontroller5 def re" ueAa tion%e( rai"e e end5 end la"" O"er"4ontroller<e"t K <e"t::Onit::<e"t4a"e fixture" :u"er" def "etup @ ontroller ! O"er"4ontroller.new @re@ue"t ! L tion4ontroller::<e"t2e@ue"t.new @re"pon"e ! L tion4ontroller::<e"t2e"pon"e.new end def te"tAindex get :index a""ertAredire tedAto : ontroller !. QloginQJ :a tion !. QloginQ end def te"tAindexAwit,Alogin @re@ue"t."e""ion):u"er+ ! u"er"%:ronaldo(.id get :index a""ertAre"pon"e :"u e"" a""ertAtag :tag !. QtableQJ : ,ildren !. S : ount !. O"er. ount N 1J :only !. S :tag !. QtrQ T T end end

Aqui estamos testan o se e0iste uma tabela com um nPmero pa#inao6 mas isso tambJm po eria ser consi era o "acilmente.

e linhas e0atamente i#ual ao nPmero

usurios que temos mais um Sque seria o cabealhoT. Bo estamos levan o em conta uma possIvel

*!*

Continuan o6 po erIamos ter al#um assim tambJmA

re@uire 9ile.dirname%AA97D1AA( N H/../te"tA,elperH re@uire Hu"er"A ontrollerH ? 2e-rai"e error" aug,t by t,e ontroller. la"" O"er"4ontroller5 def re" ueAa tion%e( rai"e e end5 end la"" O"er"4ontroller<e"t K <e"t::Onit::<e"t4a"e fixture" :u"er" def "etup @ ontroller ! O"er"4ontroller.new @re@ue"t ! L tion4ontroller::<e"t2e@ue"t.new @re"pon"e ! L tion4ontroller::<e"t2e"pon"e.new end def te"tAindex get :index a""ertAredire tedAto : ontroller !. QloginQJ :a tion !. QloginQ end def te"tAindexAwit,Alogin @re@ue"t."e""ion):u"er+ ! u"er"%:ronaldo(.id get :index a""ertAre"pon"e :"u e"" a""ertAtag :tag !. QtableQJ : ,ildren !. S : ount !. O"er. ount N 1J :only !. S :tag !. QtrQ T T a""ertAtag :tag !. QtdQJ : ontent !. u"er"%:ronaldo(.name end end

/stamos acima testan o o conteP o e uma Pnica cJlula a tabela e usurios. :estes "uncionais so Pteis para testar um controller em in ivi ual e pelos tipos e testes acima para ter uma i Jia e0ecuo e como "arIamos na maior parte epen e os casos. :estar A=a0 J um pouco mais complica o porque a e respostas te0tuais. .m plu#in especI"ico para isso e Qava-cript mas = e0istem plu#ins inte#ra os a "erramentas pr<prias para isso que o que veri"icao

permitem um teste mais completo

po e ser encontra o no en ereoA httpAZZan thennothin#.netZarchivesZ*$$1Z$*Z$5Zselenium;on;rails. + Pltimo e0emplo o que temos em termos e testes no Rails so os testes e inte#rao menciona os e lo#in. A tItulo e

anteriormente que nos permitem testar "uncionali a e ao lon#o po erIamos ter #era o um teste e0emplo6 vamos "a>er =ustamente isso. Primeiro6 vamos #erar o teste em siA

e vrios controllers. /m nossa aplicao6

esses6 por e0emplo6 para veri"icar o nosso processo

ronaldo@minerva:~/tmp/gtd$ " ript/generate integrationAte"t login exi"t" te"t/integration/ reate te"t/integration/loginAte"t.rb

/ a#ora6 e itar o arquivoA

*!'

re@uire Q?S9ile.dirname%AA97D1AA(T/../te"tA,elperQ la"" Dogin<e"t K L tion4ontroller::7ntegration<e"t fixture" :u"er" def te"tAlogin u"er ! u"er"%:ronaldo( get Q/,omeQ a""ertAredire tedAto Q/login/loginQ followAredire tW a""ertAre"pon"e :"u e""

po"t Q/login/loginQ a""ertAre"pon"e :"u e"" a""ertAe@ual Q7nvalid login and/or pa""word.QJ fla",):noti e+ po"t Q/login/loginQJ :login !. u"er.loginJ :pa""word !. u"er.pa""word a""ertAredire tedAto Q/,omeQ followAredire tW a""ertAtag :tag !. QdivQJ :attribute" !. S :id !. QeditAformQ T end end

Bote que o arquivo testa uma sJrie postan o

e opera&es em vrios controllers6 se#uin o re irecionamentos6 e teste e J bastante po eroso e

a os6 e veri"ican o conteP o quan o necessrio. /sse tipo

po e ser6 inclusive6 aumenta o para manipular iversas sess&es simultLneas se esse "or o caso. Ro an o o teste temosA

ronaldo@minerva:~/tmp/gtd$ ra#e te"t:integration %in /,ome/ronaldo/tmp/gtd( /u"r/bin/ruby1.8 -7lib:te"t Q/u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader.rbQ Qte"t/integration/loginAte"t.rbQ Doaded "uite /u"r/lib/ruby/gem"/1.8/gem"/ra#e-'.R.1/lib/ra#e/ra#eAte"tAloader >tarted . 9ini",ed in '.1*&65& "e ond". 1 te"t"J 8 a""ertion"J ' failure"J ' error" Doaded "uite /u"r/bin/ra#e >tarted 9ini",ed in '.'''31$ "e ond". ' te"t"J ' a""ertion"J ' failure"J ' error"

?sso encerra o nossa sesso sobre testes. /mbora se=a uma intro uo bem rpi a6 esperamos que tenha si o o su"iciente para mostrar como essa parte J importante e po erosa em suas aplica&es. Lembre;se e comear a testar mesmo antes e esenvolver o que voc@ precisa6 e e e criar testes su"icientemente

completos e comple0os para veri"icar plenamente a sua aplicao testan o es e mJto os customi>a os em mo elos e a os atJ intera&es entre vrios controllers.

*!4

IMPLANTAO
/m al#um momento6 obviamente6 voc@ ter que implantar a sua aplicao em um servi or. Bo caso o Rails6 e0istem etalhes e>enas e op&es para implantao6 consi eran o vrios aspectos e necessi a es e C%? e cluster o processo. + Rails po e ro ar em conte0tos que vo e servi ores Eeb customi>a os. /ntrar em esse tutorial6 mas

o como instalar o Rails sob um servi or como o Apache no J o prop<sito

po emos tecer al#umas consi era&es sobre o processo e enviar a aplicao para o servi or. Para reali>ar esse trabalho6 e0iste uma "erramenta especI"ica cria a para o Rails que automati>a o processo6 controlan o vers&es e reali>an o outras tare"as especI"icas e implantao como6 por e0emplo6 reinicar o servi or Eeb em caso e necessi a e. /ssa "erramenta J chama a e Capistrano. Para instal;la6 si#a a rota comumA

ronaldo@minerva:~/tmp/gtd$ "udo gem in"tall

api"trano

Depos

e instala o6 voc@ po e ro ar o coman o se#uinte para ver se tu o a "erramenta est "uncionan o

corretamenteA

ronaldo@minerva:~/tmp/gtd$

ap -,

+ que precisamos a#ora J a icionar a "uncionali a e necessria M nossa aplicao com o coman o abai0oA

ronaldo@minerva:~/tmp/gtd$ ap --apply-to . X<G exi"t" onfig reate onfig/deploy.rb exi"t" lib/ta"#" reate lib/ta"#"/ api"trano.ra#e Doaded "uite /u"r/bin/ ap >tarted 9ini",ed in '.'''&6 "e ond". ' te"t"J ' a""ertion"J ' failure"J ' error"

/sse coman o a iciona novas tare"as ao coman o ra8e

a aplicao6 permitin o que con"i#uremos e

e0ecutemos novos coman os necessrios para a implementao. )amos "a>er al#uns testes a#ora consi eran o somente uma aplicao simples6 sem balanceamento vers&es para um ou mais servi or6 controlan o;as corretamente. Precisamos6 primeiro6 con"i#urar nossas op&es cria o em nosso iret<rio configA e implantao6 e itan o o arquivo deploy.rb6 que "oi e

car#a ou qualquer coisa como isso6 embora o Capistrano se=a po eroso o su"iciente no s< para enviar

*!5

"et :appli ationJ QgtdQ "et :repo"itoryJ Q"vnN"",://yourdomain. om/repo"itory/gtd/trun#Q role :webJ Qyourdomain. omQ role :appJ Qyourdomain. omQ role :dbJ QyourdomainJ omQJ :primary !. true "et :deployAtoJ Q/,ome/ronaldo/web/gtd/Q "et :u"erJ QronaldoQ

+ arquivo acima "oi re u>i o ao mInimo6 mostran o um reposit<rio -ubversioK servi ores Eeb6 e aplicao e e banco e a os con"i#ura o Sno nosso caso o mesmoTK o iret<rio para on e as vers&es sero envia asK e o usurio remoto que e0ecutar esses coman os. A con"i#urao acima obviamente assume que voc@ possui um reposit<rio -ubversion o c< i#o que estamos ro an oHsem o qual o coman o no ro ar. 7eito isso6 precisamos a#ora ro ar um coman o para iniciali>ar nossas estruturasA

ronaldo@minerva:~/tmp/gtd$ ra#e remote:exe L4<7:8!"etup %in /,ome/ronaldo/tmp/gtd( loading onfiguration /u"r/lib/ruby/gem"/1.8/gem"/ api"trano1.&.'/lib/ api"trano/re ipe"/"tandard.rb loading onfiguration ./ onfig/deploy.rb P exe uting ta"# "etup P exe uting Qm#dir -p -m RR5 /,ome/ronaldo/web/gtd/relea"e" /,ome/ronaldo/web/gtd/",ared/"y"tem [[En m#dir -p -m RRR /,ome/ronaldo/web/gtd/",ared/log [[En m#dir -p -m RRR /,ome/ronaldo/web/gtd/",ared/pid"Q "erver": )Qyourdomain. omQ+ =a""word: PPPPPP )yourdomain. om+ exe uting ommand fini",ed ommand

+ coman o acima cria o que J necessrio para a implantao. Po emos a#ora enviar os nossos arquivos para o servi or.

ronaldo@minerva:~/tmp/gtd$ ra#e deploy %in /,ome/ronaldo/tmp/gtd( PP 7nvo#e deploy %fir"tAtime( PP 7nvo#e remote:deploy %fir"tAtime( PP 1xe ute remote:deploy loading onfiguration /u"r/lib/ruby/gem"/1.8/gem"/ api"trano1.&.'/lib/ api"trano/re ipe"/"tandard.rb loading onfiguration ./ onfig/deploy.rb P exe uting ta"# deploy P exe uting ta"# update PP tran"a tion: "tart P exe uting ta"# updateA ode P @uerying late"t revi"ion... =a""word: PPPPPP P exe uting Qif )) W -d /,ome/ronaldo/web/gtd/relea"e"/&''*1''&'*$'&8 ++5 t,enEn "vn o -@ -r1 "vnN"",://yourdomain. om/repo"itory/gtd/trun# /,ome/ronaldo/web/gtd/relea"e"/&''*1''&'*$'&8 [[En %te"t -e /,ome/ronaldo/web/gtd//revi"ion".log MM %tou , /,ome/ronaldo/web/gtd//revi"ion".log [[ ,mod *** /,ome/ronaldo/web/gtd//revi"ion".log(( [[ e ,o \date NEQYF-Ym-Yd Y;:YB:Y>EQ\ $O>12 1 &''*1''&'*$'&8 .. /,ome/ronaldo/web/gtd//revi"ion".log5En fiQ "erver": )Qyourdomain. omQ+ =a""word: PPPPPP )yourdomain. om+ exe uting ommand

*!1

)out :: yourdomain. om+ =a""word: )out :: yourdomain. om+ "ubver"ion i" a"#ing for a pa""word )out :: yourdomain. om+ =a""word: )out :: yourdomain. om+ "ubver"ion i" a"#ing for a pa""word ommand fini",ed P exe uting Qrm -rf /,ome/ronaldo/web/gtd/relea"e"/&''*1''&'*$'&8/log /,ome/ronaldo/web/gtd/relea"e"/&''*1''&'*$'&8/publi /"y"tem [[En ln -nf" /,ome/ronaldo/web/gtd/",ared/log /,ome/ronaldo/web/gtd/relea"e"/&''*1''&'*$'&8/log [[En ln -nf" /,ome/ronaldo/web/gtd/",ared/"y"tem /,ome/ronaldo/web/gtd/relea"e"/&''*1''&'*$'&8/publi /"y"temQ "erver": )Qyourdomain. omQ+ )yourdomain. om+ exe uting ommand ommand fini",ed P exe uting Qte"t -d /,ome/ronaldo/web/gtd/",ared/pid" [[ En rm -rf /,ome/ronaldo/web/gtd/relea"e"/&''*1''&'*$'&8/tmp/pid" [[ En ln -nf" /,ome/ronaldo/web/gtd/",ared/pid" /,ome/ronaldo/web/gtd/relea"e"/&''*1''&'*$'&8/tmp/pid"5 trueQ "erver": )Qyourdomain. omQ+ )yourdomain. om+ exe uting ommand ommand fini",ed P exe uting ta"# "ymlin# P exe uting Ql" -x1 /,ome/ronaldo/web/gtd/relea"e"Q "erver": )Qyourdomain. omQ+ )yourdomain. om+ exe uting ommand ommand fini",ed P exe uting Qln -nf" /,ome/ronaldo/web/gtd/relea"e"/&''*1''&'*$'&8 /,ome/ronaldo/web/gtd/ urrentQ "erver": )Qyourdomain. omQ+ )yourdomain. om+ exe uting ommand ommand fini",ed PP tran"a tion: ommit P exe uting ta"# re"tart P exe uting Q"udo /,ome/ronaldo/web/gtd/ urrent/" ript/pro e""/reaperQ "erver": )Qyourdomain. omQ+ )yourdomain. om+ exe uting ommand PP )out :: yourdomain. om+ 4ouldnHt find any pro e"" mat ,ing: /,ome/ronaldo/web/gtd/ urrent/publi /di"pat ,.f gi ommand fini",ed PP 1xe ute deploy

PP PP PP PP

-e houver c< i#o no reposit<rio6 o resulta o J que a verso mais recente J veri"ica a e lana a no iret<rio correto a aplicao. -e houver processos ativos ro an o com a verso anti#a eles sero reinicia os con"orme a necessi a e. Bo caso acima6 voc@ po e ver que essa reiniciali>ao "alhou porque no con"i#uramos um servi or Eeb. 7inalmente6 se voc@ olhar o iret<rio a aplicao6 ver o se#uinte a#oraA

root@bitbu #et:/,ome/ronaldo/web/gtd? l" -l total 1& lrwxrwxrwx 1 ronaldo ronaldo $5 &''*-1'-'& /,ome/ronaldo/web/gtd/relea"e"/&''*1''&'*$'&8 drwxrwxr-x R ronaldo ronaldo $'6* &''*-1'-'& -rw-rw-rw- 1 ronaldo ronaldo &&5 &''*-1'-'& drwxr-xr-x 5 ronaldo ronaldo $'6* &''*-1'-'&

'3:$R

urrent -.

'3:$R relea"e" '3:$R revi"ion".log '3:&8 ",ared

:emos um iret<rio e vers&es e uma verso corrente. /mbora a ao acima no envie o banco e0istem e>enas e a os6 uma as tare"as o Capistrano "a> =ustamente isso. / o

e outras tare"as para controlar vrias aspectos

a implantao. V "cil ver como o uso

Capistrano "acilita enormemente a implantao no servi or.

*!!

Para ler mais e enten er to as as outras possibili a es en ereo abai0oA http://manuals.rubyonrails.com/read/boo3/#$

a "erramenta6 consulte a sua

ocumentao no

AMBIENTES DE DESENVOLVIMENTO
Desenvolver com "i>emos atJ o momento6 usan o apenas a linha sistemas operacionais em que o "rameGor8 est sen o usa o. .ma as "erramentas em especial6 o Ra Rails6 que J basea o no /clipse6 possui uma #ama e e coman o e um e itor o e te0tos po e parecer conveniente mas "erramentas esto sur#in o para a=u ar a vi a esenvolve or Rails6 nos vrios

caracterIsticas volta os para o Rails que poupa uma quanti a e substancial encontrar o Ra Rails em http://www.radrails.org/6 sen o que e0istem vers&es "uncionali a es

e trabalho. )oc@ po e o mesmo compila as iretamente as

previamente para Ein oGs6 Linu0 e (acintosh. Caso voc@ queira6 voc@ po e inte#rar

o mesmo a uma instalao /clipse comum6 usan o up ate sites. /ssa Pltima maneira J

bem conveniente para aqueles que = esto usan o o /clipse para outros tipos e esenvolvimento.

*!5

A tela acima mostra viso toma a lo#o ap<s ro armos os testes Ra8e6 instalao e plu#ins inte#ra a6 ocumentao6 e e>enas

e uni a e

a aplicao6 que no tiveram o

nenhuma "alha. Como po emos ver6 temos nave#ao6 e io com sinta0e pr<pria6 tare"as especI"icas tornam o Ra Rails um e0celente ambiente para pro=etos Rails. Com um pouco e es"oro6 J possIvel tambJm epurar aplica&es Rails

e outras pequenas "uncionali a es que

iretamente no Ra Rails6 como

mostra a tela abai0oA

?nstru&es para isso po em ser encontra as no pr<prio site o Ra Rails. /u estou usan o o Ra Rails es e sua verso $.*6 lana a h quase um ano atrsHa verso atual J a $.!1H e estou bastante satis"eito com o ambiente. Apesar e al#uns problemas em al#unas vers&es interme irias6 a verso atual J uma "erramenta que vale a pena pelo menos testar. Duas outras possibili a es que eu ain a no testei so6 respectivamenteA RIDE-MEA um ?D/ Rails para Ein oGs6 "amiliar para usurios o )isual -tu io. http://www.pro%ectrideme.com/
*!2

KDevelopA + ?D/ pa ro para o FD/ possui suporte ao Rails em suas vers&es mais recentes. http://www.3de!elop.org/

RAKE A SEU SERVIO


AlJm e to as os coman os que vimos para o ra3e atJ o momento6 outros coman os po em nos ser bem Pteis. .m eles6 por e0emplo6 so as estatIsticas o pro=eto6 que po emos ver abai0oA

ronaldo@minerva:~/tmp/gtd$ ra#e "tat" %in /,ome/ronaldo/tmp/gtd( N----------------------N-------N-------N---------N---------N-----N-------N M 8ame M Dine" M D:4 M 4la""e" M Bet,od" M B/4 M D:4/B M N----------------------N-------N-------N---------N---------N-----N-------N M ;elper" M &3 M &1 M ' M 1 M ' M 16 M M 4ontroller" M $'5 M 3$R M 6 M $5 M 5 M 5 M M 4omponent" M ' M ' M ' M ' M ' M ' M M 9un tional te"t" M 155 M 11$ M 1* M &5 M 1 M & M M Bodel" M 1'5 M R& M R M $ M ' M 1* M M Onit te"t" M 1&8 M 86 M R M 1& M 1 M 5 M M Dibrarie" M ' M ' M ' M ' M ' M ' M M 7ntegration te"t" M &6 M 18 M 1 M 1 M 1 M 1* M N----------------------N-------N-------N---------N---------N-----N-------N M <otal M 8$5 M **1 M $' M 88 M & M 5 M N----------------------N-------N-------N---------N---------N-----N-------N 4ode D:4: $$' <e"t D:4: &&1 4ode to <e"t 2atio: 1:'.5

Bo h na a

e cientI"ico nesse resulta o6 mas ele serve com um bom lembreteHprincipalmente

os testes

que precisamos implementar. (e ir pro utivi a e e c< i#o por linhas

e c< i#o J al#o consi era o

contrapro ucente ho=e6 mas comparar a quanti a e e c< i#o e0istente por rea a aplicao po e ser bem Ptil6 especialmente epois e nos acostumarmos com os nPmeros que evemos esperar. + coman o abai0o nos mostra tu o o que o Rails po e "a>erA

ronaldo@minerva:~/tmp/gtd$ ra#e --ta"#" %in /,ome/ronaldo/tmp/gtd( ra#e db:fixture":load ? Doad fixture" into t,e urrent environmentH" databa"e. Doad "pe ifi fixture" u"ing 97_<O21>!xJy ra#e db:migrate ? Bigrate t,e databa"e t,roug, " ript" in db/migrate. <arget "pe ifi ver"ion wit, Z12>7:8!x ra#e db:" ,ema:dump ? 4reate a db/" ,ema.rb file t,at an be portably u"ed again"t any G/ "upported by L2 ra#e db:" ,ema:load ? Doad a " ,ema.rb file into t,e databa"e ra#e db:"e""ion": lear ? 4lear t,e "e""ion" table ra#e db:"e""ion": reate ? 4reate" a "e""ion" table for u"e wit, 4X7::>e""ion::L tive2e ord>tore ra#e db:"tru ture:dump ? Gump t,e databa"e "tru ture to a >CD file ra#e db:te"t: lone ? 2e reate t,e te"t databa"e from t,e urrent environmentH" databa"e " ,ema ... ra#e te"t ? <e"t all unit" and fun tional" ra#e te"t:fun tional" ? 2un te"t" for fun tional"db:te"t:prepare ra#e te"t:integration ? 2un te"t" for integrationdb:te"t:prepare ra#e te"t:plugin" ? 2un te"t" for plugin"environment ra#e te"t:re ent ? 2un te"t" for re entdb:te"t:prepare ra#e te"t:un ommitted ? 2un te"t" for un ommitteddb:te"t:prepare ra#e te"t:unit" ? 2un te"t" for unit"db:te"t:prepare

*5$

...

Bo estamos e0ibin o tu o6 mas voc@ po e investi#ar al#umas tare"as que que voc@ usar com maior "reqR@ncia6 alJm os testes6 J claro. /m especial6 @ uma olha a nas se#uintes tare"asA db:structure:dump6 rails:update6 e doc:rails.

VIVENDO NO LIMITE
+ "uturo Al#umas o Rails parece estar #aranti o. + "rameGor8 vem #anhan o a eptos continuamente6 livros esto e>enas e i iomas e o pro#resso e novas vers&es J continuo. ois as novi a es previstas para a verso 1.*6 que est para sair a qualquer momento6 incluem sen o publica os sobre o mesmo em os #ran es t<picos em vo#a atualmenteA -uporte pa ro a R/-:6 menciona o e passa#em anteriormenteK

ActiveResource6 uma nova a io M "amIlia


ob=etos remotos e maneira transparente.

e bibliotecas

e suporte ao Rails que permite o acesso a

Caso voc@ queira e0perimentar com al#umas outras reas

essas caracterIsticas e tambJm ver o que h

e novo nas

o Rails6 voc@ po e atuali>ar a verso

o Rails em sua aplicao para a verso atualmente

presente no reposit<rio com um simples coman oA

ronaldo@minerva:~/tmp$ ra#e rail":freeze:edge

/sse coman o bai0a a reviso atual

o Rails6 colocan o;a no

iret<rio !endor/rails. +bviamente6 sen o o

c< i#o mais recente6 h sempre a possibili a e e que ele contenha bu#s que impe iram que sua aplicao ro e. Portanto6 use esse c< i#o somente para testes e nunca para pro uo. Para reverter o coman o acima6 useA

ra#e rail":unfreeze

UE FALTA

Besse tutorial no "oram incluI os al#uns assuntos porque consi eramos que no conse#uirIamos trat;los e maneira a equa a6 #eralmente por prop<sito esse ocumento. /ntre esses assuntos6 o mais importante se=a talve> o uso pr<prio6 mas cu=o uso J relativamente especI"ico e cu=a so e0tens&es ao Rails.
*51

epen erem

e um conhecimento e0terno que no se enqua ra no

e Geb services em RailsHinteressante em si e vrios pa r&es tornou invivel um

epen @ncia

tratamento rpi o o mesmo. Da mesma "orma6 no tratamos e en#ines e esenvolvimentos similares6 que

Como esse tutorial tambJm no tem o ob=etivo

e ser um material

e re"er@ncia nem uma obra e0austiva esse tutorial ocumentar ca a classe6

sobre o Rails6 somente as "un&es estritamente necessrias para o c< i#o "oram menciona as. + Rails J um

"rameGor8

e tamanho consi ervel e no estaria no espIrito

mJto o e varivel presentes no mesmo. Para isso6 e0istem livros = publica os sobre o assunto que voc@ po e encontrar "acilmente em livrarias tJcnicas. /spero que o resto o tutorial se=a o su"iciente para compensar essas "altas.

Concluso
:erminamos aqui o o tutorial. :o os os erros presentes no te0to e no c< i#o so6 obviamente6 meus. /u tomei um cui a o especial nas se&es que envolvem pro#ramao6 procuran o sempre mostrar entra a e saI a e0atas al#uma coisa tenha passa o. -e voc@ abai0o. De acor o com a licena escolhi a para este para copiar6 istribuir eZou mo i"icar esse ocumentoHque voc@ po e ler no ap@n ice AHvoc@ J livre a maneira que achar melhor. )oc@ po e6 inclusive6 plena liber a e para o que estava ei0a o "a>en o6 e voltan o para corri#ir minunciosamente o que eu mu ara6 mas sempre h a possibili a e e que escobrir al#um problema6 entre em contato no en ereo

ocumento

publicar um livro usan o o material completo6 com ou sem mo i"ica&es6 no seu pr<prio nome6 e ven @;lo pelo preo que achar =usto. ) em "rente e "aa o que bem enten erA a licena lhe isso. Caso queira me enviar um e;mail com su#est&es6 crIticas ou quaisquer outros comentrios6 no hesite. + en ereo para contato JA ronaldo?reflecti!esurface.com. Com e0ceo e pe i os e a=u a que no tem a ver com o tutorial em siHque eu teria o maior pra>er em aten er se tivesse tempo6 mas6 in"eli>mente6 esse no J casoHeu "arei o melhor para respon er to os e;mails. A minha empresa tambJm est trabalhos em Rub, on Rails caso ha=a interesse. Bo mais6 compartilhe e ivirta;se. isponIvel para

Apndice A: G ! "ree Documentation License


)ersion 1.*6 Bovember *$$* Cop,ri#ht SCT *$$$6*$$16*$$* 7ree -o"tGare 7oun ation6 ?nc. 51 7ran8lin -t6 7i"th 7loor6 3oston6 (A $*11$;1'$1 .-A /ver,one is permitte to cop, an istribute verbatim copies o" this license ocument6 but chan#in# it is not alloGe .

*5*

!" PREAMBLE
:he purpose o" this License is to ma8e a manual6 te0tboo86 or other "unctional an use"ul ocument c"reec in the sense o" "ree omA to assure ever,one the e""ective "ree om to cop, an re istribute it6 Gith or Githout mo i",in# it6 either commerciall, or noncommerciall,. -econ aril,6 this License preserves "or the author an publisher a Ga, to #et cre it "or their Gor86 Ghile not bein# consi ere responsible "or mo i"ications ma e b, others. :his License is a 8in o" ccop,le"tc6 Ghich means that erivative Gor8s o" the ocument must themselves be "ree in the same sense. ?t complements the %B. %eneral Public License6 Ghich is a cop,le"t license esi#ne "or "ree so"tGare. Ee have esi#ne this License in or er to use it "or manuals "or "ree so"tGare6 because "ree so"tGare nee s "ree ocumentationA a "ree pro#ram shoul oes. 3ut this License is not limite come Gith manuals provi in# the same "ree oms that the to so"tGare manualsK it can be use as a printe "or an, te0tual Gor86 this License boo8. Ee recommen so"tGare

re#ar less o" sub=ect matter or Ghether it is publishe

principall, "or Gor8s Ghose purpose is instruction or re"erence.

#" APPLICABILITY AND DEFINITIONS


:his License applies to an, manual or other Gor86 in an, me ium6 that contains a notice place cop,ri#ht hol er sa,in# it can be istribute Gi e6 ro,alt,;"ree license6 unlimite a resse in uration6 to use that Gor8 un er the con itions state b, the un er the terms o" this License. -uch a notice #rants a Gorl ; herein. :he is

cDocumentc6 beloG6 re"ers to an, such manual or Gor8. An, member o" the public is a licensee6 an as c,ouc. Cou accept the license i" ,ou cop,6 mo i", or permission un er cop,ri#ht laG. A c(o i"ie

istribute the Gor8 in a Ga, requirin#

)ersionc o" the Document means an, Gor8 containin# the Document or a portion o" it6 either

copie verbatim6 or Gith mo i"ications an Zor translate into another lan#ua#e. A c-econ ar, -ectionc is a name appen i0 or a "ront;matter section o" the Document that eals e0clusivel, Gith the relationship o" the publishers or authors o" the Document to the Documentas overall sub=ect Sor to relate mattersT an contains nothin# that coul "all irectl, Githin that overall sub=ect. S:hus6 i" the matters6 or o" le#al6 Document is in part a te0tboo8 o" mathematics6 a -econ ar, -ection ma, not e0plain an, mathematics.T :he relationship coul be a matter o" historical connection Gith the sub=ect or Gith relate commercial6 philosophical6 ethical or political position re#ar in# them. :he c?nvariant -ectionsc are certain -econ ar, -ections Ghose titles are esi#nate 6 as bein# those o"

?nvariant -ections6 in the notice that sa,s that the Document is release un er this License. ?" a section oes not "it the above e"inition o" -econ ar, then it is not alloGe to be esi#nate as ?nvariant. :he Document ma, contain >ero ?nvariant -ections. ?" the Document oes not i enti", an, ?nvariant -ections then there are none.
*5'

:he cCover :e0tsc are certain short passa#es o" te0t that are liste 6 as 7ront;Cover :e0ts or 3ac8;Cover :e0ts6 in the notice that sa,s that the Document is release un er this License. A 7ront;Cover :e0t ma, be at most 5 Gor s6 an a 3ac8;Cover :e0t ma, be at most *5 Gor s. A c:ransparentc cop, o" the Document means a machine;rea able cop,6 represente speci"ication is available to the #eneral public6 that is suitable "or revisin# the Gith #eneric te0t e itors or S"or ima#es compose Gi el, available raGin# e itor6 an in a "ormat Ghose

ocument strai#ht"orGar l,

o" pi0elsT #eneric paint pro#rams or S"or raGin#sT some

that is suitable "or input to te0t "ormatters or "or automatic translation to thGart or iscoura#e subsequent "or an, substantial

to a variet, o" "ormats suitable "or input to te0t "ormatters. A cop, ma e in an otherGise :ransparent "ile "ormat Ghose mar8up6 or absence o" mar8up6 has been arran#e amount o" te0t. A cop, that is not c:ransparentc is calle c+paquec. /0amples o" suitable "ormats "or :ransparent copies inclu e plain A-C?? Githout mar8up6 :e0in"o input "ormat6 La:e9 input "ormat6 -%(L or 9(L usin# a publicl, available D:D6 an 4:(L6 Post-cript or PD7 PB%6 9C7 an proprietar, Gor available6 an stan ar ;con"ormin# simple an e ite onl, b, esi#ne "or human mo i"ication. /0amples o" transparent ima#e "ormats inclu e mo i"ication b, rea ers is not :ransparent. An ima#e "ormat is not :ransparent i" use

QP%. +paque "ormats inclu e proprietar, "ormats that can be rea the machine;#enerate 4:(L6 Post-cript or PD7 pro uce

processors6 -%(L or 9(L "or Ghich the D:D an Zor processin# tools are not #enerall, b, some Gor processors "or

output purposes onl,. :he c:itle Pa#ec means6 "or a printe boo86 the title pa#e itsel"6 plus such "olloGin# pa#es as are nee e to o

hol 6 le#ibl,6 the material this License requires to appear in the title pa#e. 7or Gor8s in "ormats Ghich Gor8as title6 prece in# the be#innin# o" the bo , o" the te0t. A section c/ntitle 9Cdc means a name

not have an, title pa#e as such6 c:itle Pa#ec means the te0t near the most prominent appearance o" the

subunit o" the Document Ghose title either is precisel, 9Cd or

contains 9Cd in parentheses "olloGin# te0t that translates 9Cd in another lan#ua#e. S4ere 9Cd stan s "or a speci"ic section name mentione beloG6 such as cAc8noGle #ementsc6 cDe icationsc6 c/n orsementsc6 or c4istor,c.T :o cPreserve the :itlec o" such a section Ghen ,ou mo i", the Document means that it remains a section c/ntitle 9Cdc accor in# to this e"inition. :he Document ma, inclu e Earrant, Disclaimers ne0t to the notice Ghich states that this License applies to the Document. :hese Earrant, Disclaimers are consi ere onl, as re#ar s voi an has no e""ect on the meanin# o" this License. to be inclu e b, re"erence in this License6 but isclaimin# GarrantiesA an, other implication that these Earrant, Disclaimers ma, have is

$" VERBATIM COPYING


Cou ma, cop, an provi e istribute the Document in an, me ium6 either commerciall, or noncommerciall,6 the license notice sa,in# this License applies to the that this License6 the cop,ri#ht notices6 an

*54

Document are repro uce copies ,ou ma8e or

in all copies6 an

that ,ou a

no other con itions Ghatsoever to those o" this

License. Cou ma, not use technical measures to obstruct or control the rea in# or "urther cop,in# o" the istribute. 4oGever6 ,ou ma, accept compensation in e0chan#e "or copies. ?" ,ou istribute a lar#e enou#h number o" copies ,ou must also "olloG the con itions in section '. Cou ma, also len copies6 un er the same con itions state above6 an ,ou ma, publicl, ispla, copies.

%" COPYING IN UANTITY


?" ,ou publish printe copies Sor copies in me ia that commonl, have printe coversT o" the Document6 numberin# more than 1$$6 an an the Documentas license notice requires Cover :e0ts6 ,ou must enclose the le#ibl,6 all these Cover :e0tsA 7ront;Cover :e0ts on the "ront cover6 le#ibl, i enti", ,ou as the

copies in covers that carr,6 clearl, an

3ac8;Cover :e0ts on the bac8 cover. 3oth covers must also clearl, an visible. Cou ma, a other material on the covers in a

publisher o" these copies. :he "ront cover must present the "ull title Gith all Gor s o" the title equall, prominent an ition. Cop,in# Gith chan#es limite to the covers6 as lon# as the, preserve the title o" the Document an satis", these con itions6 can be treate as verbatim cop,in# in other respects. ?" the require te0ts "or either cover are too voluminous to "it le#ibl,6 ,ou shoul put the "irst ones liste Sas man, as "it reasonabl,T on the actual cover6 an continue the rest onto a =acent pa#es. ?" ,ou publish or istribute +paque copies o" the Document numberin# more than 1$$6 ,ou must either oGnloa e istribution

inclu e a machine;rea able :ransparent cop, alon# Gith each +paque cop,6 or state in or Gith each +paque cop, a computer;netGor8 location "rom Ghich the #eneral netGor8;usin# public has access to usin# public;stan ar material. ?" ,ou use the latter option6 ,ou must ta8e reasonabl, pru ent steps6 Ghen ,ou be#in location until at least one ,ear a"ter the last time ,ou a#ents or retailersT o" that e ition to the public. ?t is requeste 6 but not require 6 that ,ou contact the authors o" the Document Gell be"ore re istributin# an, lar#e number o" copies6 to #ive them a chance to provi e ,ou Gith an up ate version o" the Document. netGor8 protocols a complete :ransparent cop, o" the Document6 "ree o" a

o" +paque copies in quantit,6 to ensure that this :ransparent cop, Gill remain thus accessible at the state istribute an +paque cop, S irectl, or throu#h ,our

&" MODIFICATIONS
Cou ma, cop, an above6 provi e istribute a (o i"ie )ersion o" the Document un er the con itions o" sections * an )ersion un er precisel, this License6 Gith the (o i"ie ' that ,ou release the (o i"ie

)ersion "illin# the role o" the Document6 thus licensin# istribution an mo i"ication o" the (o i"ie )ersion to Ghoever possesses a cop, o" it. ?n a ition6 ,ou must o these thin#s in the (o i"ie )ersionA

A. .se in the :itle Pa#e San on the covers6 i" an,T a title istinct "rom that o" the Document6 an "rom
those o" previous versions SGhich shoul 6 i" there Gere an,6 be liste in the 4istor, section o" the

*55

DocumentT. Cou ma, use the same title as a previous version i" the ori#inal publisher o" that version #ives permission.

3. List on the :itle Pa#e6 as authors6 one or more persons or entities responsible "or authorship o" the
mo i"ications in the (o i"ie requirement. )ersion6 to#ether Gith at least "ive o" the principal authors o" the Document Sall o" its principal authors6 i" it has "eGer than "iveT6 unless the, release ,ou "rom this

C. -tate on the :itle pa#e the name o" the publisher o" the (o i"ie )ersion6 as the publisher. D. Preserve all the cop,ri#ht notices o" the Document. /. A 7.
an appropriate cop,ri#ht notice "or ,our mo i"ications a =acent to the other cop,ri#ht notices. en um beloG. ?nclu e6 imme iatel, a"ter the cop,ri#ht notices6 a license notice #ivin# the public permission to use the (o i"ie )ersion un er the terms o" this License6 in the "orm shoGn in the A the Documentas license notice.

%. Preserve in that license notice the "ull lists o" ?nvariant -ections an require Cover :e0ts #iven in 4. ?nclu e an unaltere cop, o" this License. ?.
Preserve the section /ntitle title6 ,ear6 neG authors6 an no section /ntitle c4istor,c6 Preserve its :itle6 an publisher o" the (o i"ie a to it an item statin# at least the )ersion as #iven on the :itle Pa#e. ?" there is an item escribin# the (o i"ie

c4istor,c in the Document6 create one statin# the title6 ,ear6 authors6 an

publisher o" the Document as #iven on its :itle Pa#e6 then a )ersion as state in the previous sentence.

Q.

Preserve the netGor8 location6 i" an,6 #iven in the Document "or public access to a :ransparent cop, o" the Document6 an Gas base li8eGise the netGor8 locations #iven in the Document "or previous versions it in the c4istor,c section. Cou ma, omit a netGor8 location "or a on. :hese ma, be place

Gor8 that Gas publishe at least "our ,ears be"ore the Document itsel"6 or i" the ori#inal publisher o" the version it re"ers to #ives permission.

F. 7or an, section /ntitle cAc8noGle #ementsc or cDe icationsc6 Preserve the :itle o" the section6 an
preserve in the section all the substance an an Zor e ications #iven therein. tone o" each o" the contributor ac8noGle #ements in their te0t an in their titles. in the (o i"ie

L. Preserve all the ?nvariant -ections o" the Document6 unaltere (. Delete an, section /ntitle
)ersion.

-ection numbers or the equivalent are not consi ere part o" the section titles. c/n orsementsc. -uch a section ma, not be inclu e

B. Do not retitle an, e0istin# section to be /ntitle


?nvariant -ection.

c/n orsementsc or to con"lict in title Gith an,

+. Preserve an, Earrant, Disclaimers.


?" the (o i"ie )ersion inclu es neG "ront;matter sections or appen ices that quali", as -econ ar, -ections an contain no material copie "rom the Document6 ,ou ma, at ,our option esi#nate some or all o" these )ersionas sections as invariant. :o o this6 a their titles to the list o" ?nvariant -ections in the (o i"ie

license notice. :hese titles must be istinct "rom an, other section titles. Cou ma, a a section /ntitle c/n orsementsc6 provi e it contains nothin# but en orsements o" ,our

*51

(o i"ie

)ersion b, various parties;;"or e0ample6 statements o" peer revieG or that the te0t has been

approve b, an or#ani>ation as the authoritative e"inition o" a stan ar . Cou ma, a :e0t an a passa#e o" up to "ive Gor s as a 7ront;Cover :e0t6 an a passa#e o" up to *5 Gor s as a 3ac8; o" the list o" Cover :e0ts in the (o i"ie )ersion. +nl, one passa#e o" 7ront;Cover e b, ,ou or b, arran#ement e b, Sor throu#h arran#ements ma e b,T an, one entit,. ?" the anotherK but ,ou ma, replace the ol

Cover :e0t6 to the en

one o" 3ac8;Cover :e0t ma, be a

Document alrea , inclu es a cover te0t "or the same cover6 previousl, a ma e b, the same entit, ,ou are actin# on behal" o"6 ,ou ma, not a one6 on e0plicit permission "rom the previous publisher that a :he authorSsT an publisherSsT o" the Document

e the ol one.

o not b, this License #ive permission to use their names

"or publicit, "or or to assert or impl, en orsement o" an, (o i"ie )ersion.

'" COMBINING DOCUMENTS


Cou ma, combine the Document Gith other ocuments release un er this License6 un er the terms e"ine in section 4 above "or mo i"ie -ections o" all o" the ori#inal versions6 provi e that ,ou inclu e in the combination all o" the ?nvariant list them all as ?nvariant -ections o" ,our ocuments6 unmo i"ie 6 an

combine Gor8 in its license notice6 an that ,ou preserve all their Earrant, Disclaimers. :he combine Gor8 nee onl, contain one cop, o" this License6 an multiple i entical ?nvariant -ections

ma, be replace

Gith a sin#le cop,. ?" there are multiple ?nvariant -ections Gith the same name but in# at the en o" it6 in parentheses6 the

i""erent contents6 ma8e the title o" each such section unique b, a

name o" the ori#inal author or publisher o" that section i" 8noGn6 or else a unique number. (a8e the same a =ustment to the section titles in the list o" ?nvariant -ections in the license notice o" the combine Gor8. ?n the combination6 ,ou must combine an, sections /ntitle "ormin# one section /ntitle c4istor,c in the various ori#inal ocuments6

c4istor,cK li8eGise combine an, sections /ntitle

cAc8noGle #ementsc6 an

an, sections /ntitle cDe icationsc. Cou must elete all sections /ntitle c/n orsements.c

(" COLLECTIONS OF DOCUMENTS


Cou ma, ma8e a collection consistin# o" the Document an in the collection6 provi e other ocuments release un er this License6 an replace the in ivi ual copies o" this License in the various ocuments Gith a sin#le cop, that is inclu e that ,ou "olloG the rules o" this License "or verbatim cop,in# o" each o" the ocuments in all other respects. Cou ma, e0tract a sin#le provi e ocument "rom such a collection6 an istribute it in ivi uall, un er this License6 ocument6 an "olloG this License in all other

,ou insert a cop, o" this License into the e0tracte

respects re#ar in# verbatim cop,in# o" that ocument.

*5!

)" AGGREGATION *ITH INDEPENDENT *ORKS


A compilation o" the Document or its erivatives Gith other separate an in or on a volume o" a stora#e or "rom the compilation is not use istribution me ium6 is calle in epen ent ocuments or Gor8s6 Ghat the an ca##re#atec i" the cop,ri#ht resultin#

to limit the le#al ri#hts o" the compilationas users be,on

in ivi ual Gor8s permit. Ehen the Document is inclu e in an a##re#ate6 this License oes not appl, to the other Gor8s in the a##re#ate Ghich are not themselves erivative Gor8s o" the Document. ?" the Cover :e0t requirement o" section ' is applicable to these copies o" the Document6 then i" the Document is less than one hal" o" the entire a##re#ate6 the Documentas Cover :e0ts ma, be place on covers that brac8et the Document Githin the a##re#ate6 or the electronic equivalent o" covers i" the Document is in electronic "orm. +therGise the, must appear on printe covers that brac8et the Ghole a##re#ate.

+" TRANSLATION
:ranslation is consi ere a 8in o" mo i"ication6 so ,ou ma, istribute translations o" the Document un er ition to the all the the terms o" section 4. Replacin# ?nvariant -ections Gith translations requires special permission "rom their cop,ri#ht hol ers6 but ,ou ma, inclu e translations o" some or all ?nvariant -ections in a license notices in the Document6 an /n#lish version o" this License an ori#inal version Gill prevail. ?" a section in the Document is /ntitle cAc8noGle #ementsc6 cDe icationsc6 or c4istor,c6 the requirement an, Earrant, Disclaimers6 provi e ori#inal versions o" these ?nvariant -ections. Cou ma, inclu e a translation o" this License6 an the ori#inal versions o" those notices an

that ,ou also inclu e the ori#inal isclaimers. ?n case o" a isclaimer6 the

isa#reement betGeen the translation an

the ori#inal version o" this License or a notice or

Ssection 4T to Preserve its :itle Ssection 1T Gill t,picall, require chan#in# the actual title.

," TERMINATION
Cou ma, not cop,6 mo i",6 sublicense6 or istribute the Document e0cept as e0pressl, provi e "or un er this License. An, other attempt to cop,6 mo i",6 sublicense or istribute the Document is voi 6 an Gill automaticall, terminate ,our ri#hts un er this License. 4oGever6 parties Gho have receive "ull compliance. copies6 or

ri#hts6 "rom ,ou un er this License Gill not have their licenses terminate so lon# as such parties remain in

#!" FUTURE REVISIONS OF THIS LICENSE


:he 7ree -o"tGare 7oun ation ma, publish neG6 revise to a versions o" the %B. 7ree Documentation License i""er in etail "rom time to time. -uch neG versions Gill be similar in spirit to the present version6 but ma, ress neG problems or concerns. -ee http://www.gnu.org/copyleft/. istin#uishin# version number. ?" the Document speci"ies that a

/ach version o" the License is #iven a

*55

particular numbere publishe Snot as a

version o" this License cor an, later versionc applies to it6 ,ou have the option o" con itions either o" that speci"ie version or o" an, later version that has been oes not speci", a version ra"tT b, the 7ree -o"tGare Snot as a ra"tT b, the 7ree -o"tGare 7oun ation. ?" the Document

"olloGin# the terms an

number o" this License6 ,ou ma, choose an, version ever publishe 7oun ation.

HO* TO USE THIS LICENSE FOR YOUR DOCUMENTS


:o use this License in a ocument ,ou have Gritten6 inclu e a cop, o" the License in the ocument an put the "olloGin# cop,ri#ht an license notices =ust a"ter the title pa#eA Cop,ri#ht ScT C/AR C+.R BA(/. Permission is #rante to cop,6 istribute an Zor mo i", this ocument un er the terms o" the %B. 7ree Documentation License6 )ersion 1.* or an, later version publishe b, the 7ree -o"tGare 7oun ationK Gith no ?nvariant -ections6 no 7ront;Cover :e0ts6 an no 3ac8;Cover :e0ts. A cop, o" the license is inclu e in the section entitle c%B. 7ree Documentation Licensec. ?" ,ou have ?nvariant -ections6 7ront;Cover :e0ts an thisA Gith the ?nvariant -ections bein# L?-: :4/?R :?:L/-6 Gith the 7ront;Cover :e0ts bein# L?-:6 an Gith the 3ac8;Cover :e0ts bein# L?-:. ?" ,ou have ?nvariant -ections Githout Cover :e0ts6 or some other combination o" the three6 mer#e those tGo alternatives to suit the situation. ?" ,our ocument contains nontrivial e0amples o" pro#ram co e6 Ge recommen releasin# these e0amples in parallel un er ,our choice o" "ree so"tGare license6 such as the %B. %eneral Public License6 to permit their use in "ree so"tGare. 3ac8;Cover :e0ts6 replace the cGith...:e0ts.c line Gith

*52

Você também pode gostar