Archive for the ‘Rails’ Category
Ops! RailsTree, de novo?
Monday, November 10th, 2008RESTful - Parent Load, com método preload
Friday, August 29th, 2008Para quem usa RESTful e Nested Resources existe uma ação de carregamento do objeto pai na maioria dos controllers filho.
Se você não entendeu nada do que eu falei, dê uma lida em
RESTful Rails Development, by Ralf Wirdemann & Thomas Baustert
Por exemplo tenho dois models um Person e o outro Personality sendo que Person tem uma Personality e Personality pertence a Person.
Ficando assim o relacionamento no AR
#app/models/person.rb class Person < ActiveRecord::Base has_one :personality end
#app/models/personality.rb class Personality < ActiveRecord::Base belongs_to :person end
e as rotas desta forma
ActionController::Routing::Routes.draw do |map| map.resources :personalities, :belongs_to => :people, :singular => "personality" map.resources :people, :has_one => :personality end
Ok até agora. “Feitisso” podemos criar um registro Person via /people/new e depois criar um registro Personality via /people/1/personality/new
Quando for criado o novo registro Personality o id do pai(Person) vai como parametro
params[:person_id]
Então você já deve ter visto muito a estrategia de carregamento do objeto pai em uma variável de instância via filtro, em um construção do tipo abaixo:
class PersonalitiesController < ApplicationController before_filter :get_person private def get_person @person = Person.find(params[:person_id]) end end
Portando antes de executar a action o pai é carregado via filtro.
Para evitar está estrategia que estava repetindo em quase todos meus controllers crie o método preload.
Com preload posso ter uma contrução mais clara e com o mesmo efeito. Então agora posso fazer assim
class PersonalitiesController < ApplicationController preload :person end
Podemos também utilizar include, order, limit, etc
class PersonalitiesController < ApplicationController preload :person, :include => :personality end
Ou até especificar em quais actions o preload será utilizado
class PersonalitiesController < ApplicationController preload :person, {:include => :personality}, {:only => [:create]} end
Olha a origem da mágica
class ApplicationController < ActionController::Base def self.preload_object(name,options,filter_options={} ) before_filter(filter_options) do |controller| controller.instance_variable_set("@#{name}", name.to_s.camelize.constantize.find(controller.params["#{name}_id"], options)) end end end
Apenas um método de classe dentro do ApplicationController e um pouco de meta programação.
Agora vou tentar explicar o médodo preload.
Começando por
name.to_s.camelize.constantize
o name vem como Symbol no nosso caso :person, então temos
name.to_s #=> "person"
O método camelize analiza o conteúdo da String e adapta ao padrão de nome de classes utilizadas em Ruby, exemplo “foo_bar” camelizado passa a ser “FooBar”.
name.to_s.camelize #=> "Person"
Invocando a constante
name.to_s.camelize.constantize #=> Person
ou poderia utilizar
Object.const_get name.to_s.camelize
Já que tenho a classe Person utilizo o find passando o padrão pai_id.
O bloco do before_filter passa um yield do controller, precisamos do controller neste escopo pois estamos em um contexto estático, por conseguinte apenas params[:pai_id] não é visível então utilizei controller.params[:pai_id]
E por último criar a instância @pai apontando para o retorno do Person.find, vou dar um zoom no código
class ApplicationController < ActionController::Base def self.preload_object(name,options,filter_options={} ) before_filter(filter_options) do |controller| parent_id = controller.params["#{name}_id"] find_return = name.to_s.camelize.constantize.find(parent_id) controller.instance_variable_set("@#{name}", find_return) end end end
Ou você prefere a versão One-Line-Brain-Fucker?
class ApplicationController < ActionController::Base def self.preload_object(name,options,filter_options={} ) before_filter(filter_options) { |controller| controller.instance_variable_set("@#{name}", name.to_s.camelize.constantize.find(controller.params["#{name}_id"], options)) } end end
Mais DRY, mais DRY …
Executive IT Meeting em Goiânia
Friday, October 26th, 2007
Gostaria de Convidar a todos a participarem do Executive IT Meeting l em Goiânia, 29..31 de outubro de 2007.
Vou representar a comunidade(espero ser capaz) ![]()
O meu amigo Alexandro Lima fez uma Charge para o evento.

Nossa participação será no dia 31 na parte da tarde:
Palestra: Linguagem Ruby - Minerando e Lapidando.
Filosofia, idiossincrasia e pragmática da linguagem.
Tutorial: Ruby on Rails - Overview sobre o Framework do Ano.
Desenvolvendo um aplicação MVC em Rails.
Espero vcs lá hein! ![]()
Rails Tree Release 0.8.5
Friday, August 10th, 2007Nova versão do plugin railstree com criação via Hash e bugfix RSS.

tabelas1=%w(starttelephony startvoip customers gateways) tabelas2=%w(teste1 teste2 ) d1=Node.new(:label => "radius", :icon => "/images/data.png", :open => true) d2=Node.new(:label => "teste", :icon => "/images/data.png", :open => false) tabelas1.each do |t| no=Node.new(:label => t, :icon => "/images/table_sql.png") d1 << no end tabelas1.each do |t| no=Node.new(:label => t, :icon => "/images/table_sql.png") d1 << no end tabelas2.each do |t| no=Node.new(:label => t, :url => 'link aqui', :icon => "/images/table_sql.png") d2 << no end tr = Tree.new(:label => "Databases[solaris]") tr << d1 tr << d2
| Version | Download | Howto | Repository |
| 0.8.5 | |
|
|
RailsTree 0.8.5
Tuesday, July 10th, 2007Estava procurando uma tree para utilizar em rails e não achei, aí migrei a tree que tinhamos desenvolvido baseado no javascript do Geir Landr[2003] do formj para um plugin rails.
Exemplo de árvore dos dois estilos por padrão.
Gnome Style(default)

Explorer Style

Mac X/Acqua Style
Me mande que coloco aqui ![]()
Anatomia
Após a instalação o railstree adiciona os seguintes arquivos no RAILS_ROOT
/lib/node.rb # o nó /lib/tree.rb # a tree que também é um nó(raíz) /public/images/tree/*.gif # imagens(pasta,documento,etc) /public/javascripts/tree.js # O script da árvore /public/stylesheets/tree.css # humm! o estilo.
Talvez o estilo da sua aplicações interfira diretamente no esboço da árvore.
Gnome Style é o default, para usar o Explorer Style descompacte img_tree_explorer.tar.gz em /public/images/tree
Instalação
Via svn
Adicione o repositório
script/plugin source svn://rubyforge.org/var/svn/railstree/vendor/plugins
Depois instale com
script/plugin install tree
Via local
Descompacte o arquivo railstree0.8.5.zip no diretório vendor/plugins do seu Rails. Entre no diretório tree e execute
ruby install.rb
O railstree funciona em conjunto com os scripts de ajax e javascripts default do rails, portando adicione na sua view o no seu layout os scripts
<%= javascript_include_tag 'prototype' %> <%= javascript_include_tag 'effects' %> <%= javascript_include_tag 'dragdrop' %> <%= javascript_include_tag 'controls' %>
e depois o script e o css do railstree
<%= stylesheet_link_tag 'tree' %> <%= javascript_include_tag 'tree' %>
ficando assim
<%= stylesheet_link_tag 'tree' %> <%= javascript_include_tag 'tree' %> <%= javascript_include_tag 'prototype' %> <%= javascript_include_tag 'effects' %> <%= javascript_include_tag 'dragdrop' %> <%= javascript_include_tag 'controls' %>
Já tá pronto pra funcionar
Usando
A idéia é básica. Um nó pode ter filhos ou não. Para criar sua estrutura siga sempre a lógica de colocar um nó dentro do outro e um objeto da classe Tree para impressão dos dados na tela.
Exemplo:
a=Node.new(:label => 'A', :url => '/letras/a') # nome , link b=Node.new(:label => 'B', :url => '/letras/b') c=Node.new(:label => 'C', :url => '/letras/c') d=Node.new(:label => 'D', :url => '/letras/d') e=Node.new(:label => 'E', :url => '/letras/e') f=Node.new(:label => 'F', :url => '/letras/f') # nó em filho a << b #adicionando b em a c << a #adicionando a em c d << e #adicionando e em d tree=Tree.new(:label => 'Root',:url=> '/letras/todas') tree << c #Taca 'c' na raiz da tree tree << d #Taca 'd' na raiz da tree tree << f #Taca 'f'(sem filho) na raiz da tree
Podemos passar blocos para os nós. Exemplo da mesma estrutura acima, usando blocos
tree=Tree.new(:label => "Root",:url =>"/letras/todas") do |t| t << Node.new(:label => "C",:url =>"/letras/c") do |n| n << Node.new(:label => "A",:url =>"/letras/a") {|a| a << Node.new(:label => "B",:url =>"/letras/b")} end end tree << Node.new(:label => "D",:url =>"/letras/d") {|d| d << Node.new(:label => "E",:url =>"/letras/E") } tree << Node.new(:label => "F",:url =>"/letras/f")
E que Deus continue inspirando Yukihiro Matsumoto…
Vc escolhe!
Tem mais uma, todo o node tem nodes e aceita um bloco(opcional)
a=Node.new("A","/letras/a") a.nodes do |n| #faça algo com os filhos end
Personalizando…
Você poderá mudar os ícones de um nó fechado ou aberto, fazer referênciar pelo atributo href de uma âncora ou onclick para acessar uma função em javascript, falar para o nó aparecer aberto ou fechado, etc.
Mudando os ícones
a=Node.new(:label => "A",:url => "/letras/a") a.icon='/images/db.png' a.icon_open='/images/outroicone.png'
Exemplo, esse código
tabelas1=%w(starttelephony startvoip customers gateways) tabelas2=%w(teste1 teste2 ) d1=Node.new(:label => "radius", :icon => "/images/data.png", :open => true) d2=Node.new(:label => "teste", :icon => "/images/data.png", :open => false) tabelas1.each do |t| no=Node.new(:label => t, :icon => "/images/table_sql.png") d1 << no end tabelas1.each do |t| no=Node.new(:label => t, :icon => "/images/table_sql.png") d1 << no end tabelas2.each do |t| no=Node.new(:label => t, :url => 'link aqui', :icon => "/images/table_sql.png") d2 << no end tr = Tree.new(:label => "Databases[solaris]") tr << d1 tr << d2
Gera isto:

Falando para um node aparecer aberto ou fechado(se tiver filhos!)
# :open => true ou false, esse valor é passado para o javascript a=Node.new(:label => "A",:url => "/letras/a", :open => true) #ou a.open=true
Link e eventos
Temos o atributo variável event_name que pode ser qualquer coisa que vc quer mais trabalha em conjunto com o atributo href, não obstante para criar um link teremos o seguinte:
Node.new(:label => "A",:url => "/letras/a")
é a mesma coisa de fazer isso
Node.new(:label => "A",:href => '/letra/a', :event_name => :href)
isso vai criar uma tag assim para o nó
<a href=’/letras/a’ > A </a>
Hummm!
Então para criar um nó que chama um javascript pode ser assim
Node.new(:label => "A", :url => "alert('nossa que doído!')", :event_name => :onclick ) #ou a=Node.new a.label="A" a.url="alert('nossa que doído!')" a.event_name= :onclick
Link for Rails
Tem um esquema legal, que é usar a mesmo mecanismo de link do Rails o link_to e o link_to_remote.
É necessário a adição da opção :base referenciando uma instância de qualquer controller para que o mecanismo interno do método url_for(rails) funcione adequadamente.
link_to
Node.new :label => "Criar usuário", :link_to => { :base => @controller, :controller => "usuarios", :action => "adicionar" , :id => 1 }
assumindo que @controller é uma instância do controller, se tiver dentro de um controller troque @controller por self ficando :base => self.
Para um roteamento padrão do Rails isso é a mesmo coisa de
n=Node.new(:label => "Criar usuário",url => "/usuarios/adicionar/1")
Pode também fazer requisições em ajax utilizando a criação padrão do link_to_remote mais :base.
link_to_remote
Node.new :label => "Adicionar usuário ", :link_to_remote => { :base => @controller, :controller => "usuarios", :update => "id_do_div", :url =>{ :action => 'adicionar', :c=> 'variavel C', :a => 'variavel A'} } }
Montando uma árvore de diretório
Vou demonstrar aqui gerando o path do RAILS_ROOT
Tree.for(RAILS_ROOT)
Pronto. Isso gera

Extra Sintaxe
t=Tree.new(:label => 'Raiz') t.child(:label => 'Pai').child(:label => 'filho').child(:label => 'espirito santo').child(:label => 'amem')
t.child(:label => 'Pai'){ |p| p.child(:label => 'filho') } #ou t.child Node.new(:label => 'Pai').child Node.new(:label => 'filho')
Para vários irmão
t.child Node.new(:label => 'a'),Node.new(:label => 'b'), Node.new(:label => 'c')
ou
t.mknodes(5) do |n,s| n.label="Link #{s}" n.url="/link/#{s}" end
Obs.: Sugestão do Ronie Uliana
Obs2.: Criação dos nodes passando Hash foi sugestão do Marcelo Júnior
rghost - Plugin ou Gem?
Tuesday, July 10th, 2007Você escolhe!!

Pra quem pediu, disponibilizei o rghost como plugin no repositório do rghost no RubyForge só descompactar no RAILS_ROOT/lib e reiniciar a aplicação.
Impressão direta via TCP/IP com RubyGhost
Tuesday, July 10th, 2007Geralmente as impressoras de médio e grande porte disponibilizam uma porta TCP conhecida como ‘porta bruta’ de número 9100. Demonstrarei aqui uma forma de imprimir diretamente neste tipo de printer, para o nosso exemplo usaremos o driver postscript genérico da Adobe(PS-Adobe-3.0).
Models Contas e Clientes
class Contas < ActiveRecord::Base belongs_to :clientes end class Clientes < ActiveRecord::Base has_one :contas end
Configurando as colunas
require 'rghost' clientes=Clientes.find :all, :include => :contas, :limit => 10000 grid=DataGrid::RailsGrid.new :width => 4 , :align => :center grid.col :codigo, :title => "Código do Cliente", :width => 5 grid.col :nome, :title => "Nome" grid.col :created_on, :title => "Data de Cadastro ", :format => :eurodate grid.col lambda { contas.login }, :title => "Login" grid.data(clientes)
Criando o documento com dados do ActiveRecord
doc=Document.new :paper => :A4, :landscape => true, :duplex => true doc.before_page_create do set Image.for("/tmp/fatura.eps") end doc.set grid doc.done
Enviando o documento
printer = TCPSocket.open('192.168.1.70', 9100) printer.write doc.render_stream(:ps)
Deve ter saído lá na impressora…
Para mais informações no RGhost - RubyForge . Documentação em português no RubyForge
Rghost v0.7 Encodings e proxy charset
Wednesday, June 13th, 2007Com a versão 0.7 podemos agora usar diferentes codificação de fontes e conversão de charset de Ruby para Postscript.
Encodings disponíveis
- AdobeExpert
- AdobeLatinEncoding
- Bengali
- CodePage1250
- CodePage1251
- CodePage1252
- CodePage1253
- CodePage1254
- CodePage1256
- CodePage1257
- CodePage1258
- CodePage874
- IsoLatin
- MacCentralEuropean
- MacCyrillice
- MacGreek
- MacHebrew
- TeX-CorkEncoding
- TeX-LGR-Greek
- TeXMathExtensionEncoding
- TeXMathItalicEncoding
- TeXMathSymbolEncoding
- TeX-T2AModified2Encoding
- TeX-T2BAdobeEncoding
- TeX-T2CAdobeEncoding
- TeX-X2AdobeEncoding
- TeX-XL2encoding
- US-ASCII
- UTF-8
Ideal para código fonte Ruby no mesmo formato dos dados do documento. Existem duas formas de setar o encoding da fonte:
Antes de usar o documento
RubyGhostConfig::GS[:font_encoding] = 'CodePage1252'
Na criação do documento
doc=Document.new :font_encoding => 'CodePage1252'
Agora quando o charset do código fonte está diferente dos dados é necessário a conversão dos formatos. Para este fim usamos um bloco retornando uma string antes da criação do documento.
Exemplo para código fonte no padrão UTF-8 com acentuação.
RubyGhostConfig::GS[:charset_convert]= lambda {|text| Iconv::iconv('latin1','utf8', text).to_s}
O gem e o manual da versão 0.7 disponível no RubyForge.
Console For The Web
Thursday, April 19th, 2007Vou demonstrar ‘uma’ solução para utilização de recursos no estilo console como irb, bash, psql, gs e outros.
A estratégia é simples, vamos abrir um pipe com a aplicação e trocar mensagens.
Já vou dizendo, vou utilizar uma variável global, sem delongas se-pode-ou-não-pode se existe é por que pode usar, mas com cautela. Isso me fez lembra do goto do C, todo mundo condenava a utilização(até eu) mas o meu professor de Linguagens Formais e Compiladores (Rafael Corvinel) me tirou das trevas. Faziamos interpretadores de gramáticas em C utilizando funções e condicionais normalmente, ele disse “esse código funciona e está bem estruturado” vamos focar agora em desempenho… “vamos fazer com goto” é meu caro a coisa funfou mais rápido dos que a forma estruturada, portando não estou mais nas trevas nem no dogmatismo. Qual é o seu foco?
A classe ConsoleForWeb
class ConsoleForWeb attr_reader :output def initialize(pipe_name,open_now=false,mode="r+") @output='' @pipe_name=pipe_name @mode=mode open if open_now end def run(input) if @io @io.puts input.to_s @io.flush else raise Exception.new("Pipe is closed") end end def open unless @io @io=IO.popen(@pipe_name,@mode) @io.sync=false Thread.new do loop do @output << "<div>#{@io.readline.chomp}</div>" end end end end def close @io.close if id @io end def closed? @io.closed? end end
No initialize é esperado o nome do pipe(executável do programa), se é para abrir o pipe durante a inicialização da instância e mode de abertura(para ler e escrever ‘r+’)
O método run executa o comando, output obtém o retorno(attr_reader) e open e close… não precisa falar.
View
Utilizei dois arquivos, o index.rhtml para criar a caixinha para ficar parecendo um console e o partial _console.rhtml que é o cara que vai renderizar as respostas dos nossos comandos. Veja.
index.rhtml
<%= stylesheet_link_tag 'scaffold' %> <%= stylesheet_link_tag 'erails' %> <%= javascript_include_tag "prototype" %> <%= javascript_include_tag "controls" %> <%= javascript_include_tag "effects" %> <%= javascript_include_tag "erails" %> <%= form_tag({:action=> "run", :controller => "testes"}, :onload=>"posload();", :id=> 'irb', :onsubmit => "return false" )%> <div class="console" id="console" onclick="posload();"> <%= render :partial => "console" %> </div> <%= end_form_tag %>
Observe que temos um javascript erails.js para enviar as informações em Ajax e atualizar o nosso console e um stylesheet chamado erails.css… o tema (disponíveis para download, lá em baixo)
_console.rhtml
<%= @output.to_s %> >><input name="caixa" class="text" onkeypress="run(event,'irb');" type="text" id="caixa" /> <script> posload(); </script>
Para cada requisição/resposta o _console.rhtml será chamado para renderizar a resposta e criar uma caixa de input.
Controller
Crie um controller chamado TestesController com duas ações, uma para index(cria o console) e a ação run que executa os comandos na classe ConsoleForWeb.
class TestesController < ApplicationController def index render :action => "index" end def run e=params[:caixa] $irb=ConsoleForWeb.new('irb --simple-prompt',true) unless $irb $irb.run(e.chomp) if e sleep 0.3 @output=$irb.output.dup render :partial => "console" end
Veja uma atribuição unica para a variável $irb portanto utilizaremos apenas uma variável global para armazenar a instância de ConsoleForWeb. Vamos brincar agora.
script/console
Vamos especializar a classe ConsoleForWeb para fazer proxy e verificação de comando, neste exemplo inibiremos os comandos exit, quit, kill e clear. Utilizaremos um console do rails
class IrbForWeb < ConsoleForWeb def initialize super('/local/projects/bossapp/script/console',true) end def run(cmd) case cmd when /^(exit|quit|kill)/: @output << "han?\n" when /^(clear|\^C)/: @output="" else super end end end
off: Esse han? é em homenagem ao Solaris 2.4.3.
No controller o método run fica assim
def run e=params[:caixa] $irb=IrbForWeb.new unless $irb $irb.run(e.chomp) if e sleep 0.3 @output=$irb.output.dup render :partial => "console" end
Exemplo script/console

Onde colocar as classes ConsoleForWeb e IrbForWeb? Eu coloquei-as no mesmo arquivo do controller por ser um teste, coloque no lib ou em outro local que satisfaça suas necessidades.
É isso. Não é a melhor e nem a pior implementação … é “uma implementação”. Os arquivos estão aqui.


