Arquivo

Arquivo de outubro, 2010

Primeira submissão para o Ruby Quicktips

30 de outubro de 2010

Há muito tempo atrás, tanto tempo que não tenho certeza examente, acho que no começo de abril de 2010, submeti uma dica para o Ruby Quicktips, um blog dedicado a apresentar dicas pequenas, interessantes e práticas de Ruby e Ruby on Rails.

Aguardei alguns dias para a publicação da dica, já prevendo submeter outras na sequência. Como minha dica não foi publicada, desencanei e esqueci disso.

Para minha surpresa, essa semana recebi um e-mail do Ruby Quicktips informando que minha submissão foi publicada. Só levou mais de 6 meses, mas tudo bem.

A minha dica foi como visualizar um modelo em formato YAML no console, algo MUITO SIMPLES, mas para alguns iniciantes em Rails não é tão óbvio.

Viewing a model in YAML
http://rubyquicktips.tumblr.com/post/1405061475/viewing-a-model-in-yaml

Agora pretendo submeter outras dicas para o Ruby Quicktips, principalmente essas que a gente vai descobrindo no dia-a-dia. Mesmo que demorem para serem publicadas, o que vale é contribuir.

Ruby , , ,

[Off Topic] Minha nova tatuagem não é do Michael Jordan

30 de outubro de 2010

Mês passado aproveite as férias para fazer mais duas tatuagens nos braços. A do braço esquerdo foi a silhueta de “alguém” dando uma enterrada de mão direita com as pernas abertas. Veja a foto:

A maioria das pessoas que vêem minha nova tatuagem estão dizendo:

Legal, uma tatuagem do Michael Jordan.

Então para esclarecer, minha nova tatuagem não é o logo Jumpman, que representa a marca Air Jordan, criada pela Nike para promover os tênis e outros artigos esportivos usados por Michael Jordan, o maior jogador de basquete de todos os tempos. Veja a diferença abaixo:

A silhueta foi extraída de uma foto minha tirada no ano de 2005, na quadra da “Escola Municipal Deputado Flores da Cunha”, na Zona Leste de São Paulo, onde rolava um basquetebol de primeira e que eu joguei por bastante tempo.

O que eu posso afirmar é que essa enterrada foi inspirada no Michael Jordan.

Esportes, Geral , , , , , , , ,

Obtendo dados originais de atributos modificados no ActiveRecord

22 de outubro de 2010

Como todo bom framework de Mapeamento Objeto-Relacional (ORM), o ActiveRecord do Ruby on Rails mantém os dados originais dos atributos que são alterados. Com isso, você obter esses valores antes de salvar os novos.

Vamos ver alguns métodos que lhe ajudam a saber quais atributos foram alterados, bem como seus valores novos e originais.

Como exemplo usaremos um classe de modelo chamada Order com os seguintes atributos:

Imaginando que já temos pedidos cadastrados no banco de dados, através do console, vamos recuperar um pedido e atribuí-lo a uma variável chamada order:
> order = Order.first
=> #<Order id: 8567520, user_id: 506715721, number: "R222442710", total: #<BigDecimal:4607440,'0.3498E2',8(8)>, state: "new", completed_at: "2010-08-07 17:24:37">
> y order
--- !ruby/object:Order
attributes:
id: "8567520"
number: R222442710
total: "34.98"
state: new
completed_at: 2010-08-07 17:24:37
user_id: "506715721"
attributes_cache: {}
=> nil

Através do método changed?, sabemos se houve alguma modificação nessa instância de Order:
> order.changed?
=> false

Vamos modificar os atributos number e state:
> order.number = "NEW012345"
=> "NEW012345"
> order.state = "in_progress"
=> "in_progress"
> order.changed?
=> true

Agora o método changed? retorna true, mas não informa quais atributos foram alterados. Para obter uma lista de todos atributos alterados, seus valores originais e seus valores novos, usamos o método changes:
> order.changes
=> {"number"=>["R222442710", "NEW012345"], “state”=>["new", "in_progress"]}

O retorno é um hash onde as chaves são o nome dos atributos alterados e os valores são um array com dois itens: o valor original do atributo e o novo valor do atributo.

Por exemplo, você poderia fazer isso para recuperar o valor original do atributo state:
> order.changes["state"][0]
=> “new”

Existe também o método privado changed_attributes que retorna uma hash contendo somente os valores originais dos atributos modificados. Temos acesso a ele usamos o método Object#send:
> order.send :changed_attributes
=> {"number"=>"R222442710", "state"=>"new"}

E o método (também privado) attribute_was, que recebe como parâmetro o nome de um atributo como string:
> order.send :attribute_was, "state"
=> "new"

Então agora você está pensando em tornar esse último método público? Esqueça! O ActiveRecord já fez melhor.

O módulo ActiveRecord::AttributesMethods declara para cada atributo do modelo os métodos existentes na classe em que seu nome se inicia com “attribute”. Vamos listar os métodos privados da nossa instância da classe Order que atendem esse padrão:
> y order.private_methods.grep /^attribute_/
---
- attribute_change
- attribute_before_type_cast
- attribute_changed?
- attribute_was
- attribute_will_change!
=> nil

Para cada método acima, existe seu correspondente por atributo no modelo. Basta substituir “attribute” pelo nome do atributo. Veja os exemplos com o atributo state na classe Order:
> order.state
=> "in_progress"
> order.state_changed?
=> true
> order.state_change
=> ["new", "in_progress"]
> order.state_was
=> “new”

Você pode criar novos métodos que ficam disponíveis para todos os atributos. Basta registrar o sufixo do método na classe modelo usando o método de classe attribute_method_suffix e criar um método privado com o padrão attribute_[sufixo] que recebe como parâmetro o nome do atributo.

Com um exemplo fica mais fácil de entender:

class Order < ActiveRecord::Base
  attribute_method_suffix "_cool?"

  private
  def attribute_cool?(attr)
    puts "Yes, #{attr} with value #{read_attribute(attr)} is cool!"
  end
end

> order.total_cool?
Yes, total with value 34.98 is cool!
=> nil

No final das contas, o que você precisa fazer para obter o valor original de um atributo modificado é chamar o método [nome_do_atributo]_was:
> order.number_was
=> "R222442710"
> order.state_was
=> "new"

Lembrando que depois que salvamos as alterações no banco de dados, todo esse estado de alterações é removido:
> order.save
=> true
> order.changed?
=> false
> order.changes
=> {}

Ruby , , , ,

Usando o Passenger 3.0 em modo standalone em aplicações Rails

19 de outubro de 2010

O Phusion Passenger é um módulo para os servidores Apache e Nginx para rodar aplicações Web Ruby, como por exemplo aplicações Ruby on Rails.

Ontem foi lançada a sua versão 3.0 do Passenger e entre as novidades está o Phusion Passenger Standalone (também chamado de Phusion Passenger Lite) que pode ser utilizado em ambiente de desenvolvimento, ao invés do Mongrel ou WEBrick.

O processo de instalar e subir o Passenger em teoria é simples, mas tive que instalar algumas dependências no meu Mac OS X para poder utilizá-lo. Abaixo listo os passos que percorri na minha instalação.

Primeiro de tudo, instalei a gem do Passenger:

$ gem install passenger

Successfully installed daemon_controller-0.2.5
Successfully installed spruz-0.1.5
Successfully installed file-tail-1.0.5
Successfully installed passenger-3.0.0
4 gems installed

Depois, todo feliz, fui iniciar o Passenger:

$ passenger start

Recebi as seguintes mensagens dizendo para atualizar a RVM:

Nginx core 0.8.52 isn’t installed

Phusion Passenger Standalone will automatically install it into:

/Users/Prodis/.passenger/standalone/3.0.0-i386-ruby1.8.7-x86_64-macosx-10.5/nginx-0.8.52

This will only be done once. Please sit back and relax while installation is
in progress.

Checking for required software…

* GNU C++ compiler… found at /usr/bin/g++
* GNU make… found at /usr/bin/make
* A download tool like ‘wget’ or ‘curl’… found at /opt/local/bin/curl
* Ruby development headers… found
* OpenSSL support for Ruby… found
* RubyGems… found
Your RVM wrapper scripts are too old. Please update them first by running ‘rvm update –head && rvm reload && rvm repair all’.

Então eu atualizei a RVM:

$ rvm update --head && rvm reload && rvm repair all

E tentei de subir o Passenger de novo:

$ passenger start

E aí obtive essas mensagens indicando que eu não tinha Curl com suporte a SSL:

Nginx core 0.8.52 isn’t installed

Phusion Passenger Standalone will automatically install it into:

/Users/Prodis/.passenger/standalone/3.0.0-i386-ruby1.8.7-x86_64-macosx-10.5/nginx-0.8.52

This will only be done once. Please sit back and relax while installation is
in progress.

Checking for required software…

* GNU C++ compiler… found at /usr/bin/g++
* GNU make… found at /usr/bin/make
* A download tool like ‘wget’ or ‘curl’… found at /opt/local/bin/curl
* Ruby development headers… found
* OpenSSL support for Ruby… found
* RubyGems… found
* Rake… found at /Users/Prodis/.rvm/wrappers/ree-1.8.7-2009.10/rake
* rack… found
* Curl development headers with SSL support… not found
* OpenSSL development headers… found
* Zlib development headers… found
* file-tail… found
* daemon_controller >= 0.2.5… found

Some required software is not installed.
But don’t worry, this installer will tell you how to install them.

Press Enter to continue, or Ctrl-C to abort.

——————————————–

Installation instructions for required software

* To install Curl development headers with SSL support:
Curl was found, but it doesn’t support SSL.
Please download Curl from http://curl.haxx.se/libcurl and make sure you install it with SSL support.

If the aforementioned instructions didn’t solve your problem, then please take
a look at the Users Guide:

/Users/Prodis/.rvm/gems/ree-1.8.7-2009.10/gems/passenger-3.0.0/doc/Users guide Standalone.html

Fui até a URL indicada, entrei na página de downloads do Curl e baixei o arquivo curl-7.21.2.zip. Descompactei o arquivo zipado e instalei o Curl com os seguintes comandos:

$ ./configure --with-ssl

$ make

$ sudo make install

Mais uma vez executei o comando para iniciar o Passenger:

$ passenger start

E dessa vez o Nginx foi instalado:

Nginx core 0.8.52 isn’t installed

Phusion Passenger Standalone will automatically install it into:

/Users/Prodis/.passenger/standalone/3.0.0-i386-ruby1.8.7-x86_64-macosx-10.5/nginx-0.8.52

This will only be done once. Please sit back and relax while installation is
in progress.

Checking for required software…

* GNU C++ compiler… found at /usr/bin/g++
* GNU make… found at /usr/bin/make
* A download tool like ‘wget’ or ‘curl’… found at /usr/local/bin/curl
* Ruby development headers… found
* OpenSSL support for Ruby… found
* RubyGems… found
* Rake… found at /Users/Prodis/.rvm/wrappers/ree-1.8.7-2009.10/rake
* rack… found
* Curl development headers with SSL support… found
* OpenSSL development headers… found
* Zlib development headers… found
* file-tail… found
* daemon_controller >= 0.2.5… found

Downloading Nginx…
# curl http://sysoev.ru/nginx/nginx-0.8.52.tar.gz -f -L -o /tmp/Prodis-passenger-standalone-28027/nginx-0.8.52.tar.gz
Installing Phusion Passenger Standalone…
[*********************************************] Copying files… -
All done!

E finalmente consegui subir o Passenger em modo standalone:

$ passenger start

=============== Phusion Passenger Standalone web server started ===============
PID file: /Users/Prodis/Lab/quick-todo/tmp/pids/passenger.3000.pid
Log file: /Users/Prodis/Lab/quick-todo/log/passenger.3000.log
Environment: development
Accessible via: http://0.0.0.0:3000/

You can stop Phusion Passenger Standalone by pressing Ctrl-C.
===============================================================================

Note que para usar o Passenger não utilizamos mais script/server ou rails server, somente o comando passenger start na raiz da aplicação Rails.

Uma coisa interessante do Phusion Passenger Standalone é que você não precisa iniciá-lo a partir da aplicação. Você pode passar como parâmetro para o comando start o caminho da sua aplicação Rails:

Prodis ~/Downloads [ree-1.8.7] $ passenger start ~/Lab/webstore/ -p 3001

=============== Phusion Passenger Standalone web server started ===============
PID file: /Users/Prodis/Lab/webstore/passenger.3001.pid
Log file: /Users/Prodis/Lab/webstore/passenger.3001.log
Environment: development
Accessible via: http://0.0.0.0:3001/

You can stop Phusion Passenger Standalone by pressing Ctrl-C.
===============================================================================

Note que eu passei também no parâmetro -p a porta em que eu quero minha aplicação fique disponível.

Para a lista completa os parâmetros do comando start do Passenger, use o help:

$ passenger start --help

Ruby , , , , , ,

Use o método tap ao invés de returning

4 de outubro de 2010

Há um tempo atrás eu falei neste post sobre o método returning em Ruby on Rails e como ele facilita a criação de uma variável já atribuindo valores a ela.

A partir da versão 2.3.9 do Ruby on Rails, o método returning da classe Object se tornou obsoleto. Seu uso irá gerar um alerta informando para usar o método tap, nativo da classe Object no Ruby, no seu lugar:

DEPRECATION WARNING: Object#returning has been deprecated in favor of Object#tap.

O intuito dessa alerta é facilitar a migração de uma aplicação Rails 2.3.9 para a nova versão 3.0, já que nessa última versão do Rails o método returning foi removido.

Vamos ver os mesmos exemplos do post anterior, agora utilizando Object#tap.

Primeiro, um exemplo criando uma variável normalmente, atribuindo valores a ela e depois retornando-a como resultado de um método:

def some_values
  values = []
  values << "first element"
  values << "second element"
  values
end

some_values # => ["first element", "second element"]

E agora usando o método tap:

def some_values
  [].tap do |values|
    values << "first element"
    values << "second element"
  end
end

some_values # => ["first element", "second element"]

E um exemplo de um método auxiliar para testes de RSpec retirado de uma aplicação real:

def variants
  [].tap do |variants|
    5.times do |priority| do
      variants << Factory.build(:variant, :priority => priority)
    end
  end
end

Ruby , , , ,