Arquivo

Textos com Etiquetas ‘Rails’

[IT Web - Ruby Fundamental] Curso grátis de Rails 4

2 de maio de 2013

RubyConf Brasil 2011: Vídeo e slides da palestra Multitenancy em Rails

7 de novembro de 2011

A RubyConf Brasil 2011, a maior conferência com foco em Ruby da América do Sul, aconteceu nos dias 3 e 4 de novembro, com muitas palestras interessantes, networking e discussões sobre Ruby e desenvolvimento de software.

Na palestra Multitenancy em Rails: cortando custos e aumentando capacidade, Ricardo Bernardelli e eu falamos sobre a mudança de arquitetura da WebStore, loja virtual desenvolvida pela equipe de SaaS da Locaweb, onde utilizamos uma opção não tão usual de multitenancy em Rails.

O vídeo da apresentação está disponível aqui, inclusive com sincronia de slides, disponibilizado pela Eventials.

Você também pode visualizar os slides no SlideShare ou fazer download do arquivo PDF.

Meu agradecimento a todos que estiveram presentes na RubyConf acompanhando a palestra ou que assistiram remotamente pela transmissão ao vivo online, e também a todos os feedbacks positivos que recebemos.

Palestrantes da RubyConf Brasil 2011 (por Daniel Cukier)

Palestrantes da RubyConf Brasil 2011 (por Daniel Cukier)

Eventos, Ruby , , , , , ,

Irei palestrar na RubyConf Brasil 2011

23 de setembro de 2011

A RubyConf Brasil é a maior conferência com foco em Ruby da América do Sul e é comparável em tamanho às maiores conferências de tecnologia no continente.

O evento desse ano acontecerá nos dias 3 e 4 de novembro, no Centro de Convenções Frei Caneca, que fica próximo à avenida Paulista em São Paulo.

Irei palestrar, juntamente com Ricardo Bernardelli, sobre a mudança de arquitetura da WebStore, loja virtual desenvolvida pela equipe de SaaS da Locaweb.

Na palestra Multitenancy em Rails: cortando custos e aumentando capacidade, iremos falar como a escolha de uma opção não tão usual de multitenancy em Rails melhorou a arquitetura da WebStore, que antes possuía 1.000 clientes, distribuídos em 12 servidores Web, e passou a utilizar apenas um servidor com mais 4.000 clientes.

As inscrições para o evento foram abertas ontem, com valor promocional de R$ 150,00 até 27/09/2011, e espera-se mais de 700 participantes, a exemplo do que aconteceu na edição do ano passado.

A programação, lista completa dos participantes e demais informações você tem no site do evento.

Eventos, Ruby , , , , , ,

2010 em livros

5 de janeiro de 2011

Estou a “plagiando” uma idéia de Phillip Calçado que fez um post em seu blog mostrando os livros lidos no ano de 2010, com um pequeno comentário sobre cada um.

Com certeza minha lista é muito mais modesta e curta, mas a idéia de compartilhar conhecimento é a mesma.

Esse post também serve para me alertar a ler mais, mesmo com toda a correria de trabalho, família, estudo e prática de esportes, gostaria de ter lido mais que 7 livros durante 2010.

Os livros são apresentados na ordem que foram lidos:

Clean Code: A Handbook of Agile Software Craftsmanship

Clean Code: A Handbook of Agile Software Craftsmanship

Robert C. Martin
Prentice Hall
August 2008

Muito bom

Todo programador deveria ler. Uncle Bob nos concede um pouco de sua vasta experiência em desenvolvimento de software, mostrando como deixar seu código mais enxuto, legível e simples. Esse livro serviu de inspiração para várias palestras e apresentações por aí sobre como escrever código de melhor qualidade.

The RSpec Book: Behaviour-Driven Development with RSpec, Cucumber, and Friends

The RSpec Book: Behaviour-Driven Development with RSpec, Cucumber, and Friends

David Chelimsky, Dave Astels, Zach Dennis, Aslak Hellesøy, Bryan Helmkamp, Dan North
The Pragmatic Programmers
December 2010

Ótimo

Essencial para quem quer aprender RSpec. Explica como seria o ciclo ideal de BDD. Também traz exemplos práticos de utilização de RSpec e Cucumber com Ruby e Ruby on Rails.

JavaScript: The Good Parts

JavaScript: The Good Parts

Douglas Crockford
O’Reilly
May 2008

Muito bom

Quem curte JavaScript irá gostar bastante. Fiz anotações sobre esse livro nesse post.

Design Patterns in Ruby

Design Patterns in Ruby

Russ Olsen
Addison-Wesley Professional
December 2007

Bom

Traz uma boa parte dos design patterns apresentados pela GoF utilizando Ruby. O que eu achei mais interessante foi a abordagem utilizada pelo autor: dado um design pattern, o mesmo é implementado de uma maneira clássica e depois reimplementado usando os recursos que o Ruby oferece, como por exemplo, metaprogramação, tornando alguns patterns totalmente diferentes de sua implementação original.

Professional ASP.NET MVC 2

Professional ASP.NET MVC 2

Jon Galloway, Scott Hanselman, Phil Haack, Scott Guthrie, Rob Conery
Wrox
June 2010

Muito bom

Sempre gostei da séria Professional da Wrox e esse livro mantém a linha de qualidade. Logo no primeiro capítulo tem um passo a passo da construção de uma pequena, mas completa, aplicação ASP.NET MVC 2. Os demais capítulos cobrem os demais recursos do framework. Só pelos autores já vale a leitura.

ASP.NET MVC 2 in Action

ASP.NET MVC 2 in Action

Jeffrey Palermo, Ben Scheirman, Jimmy Bogard, Eric Hexter, Matthew Hinze
Manning
June 2010

Regular

Talvez se eu não tivesse lido o livro da Wrox antes teria classificado melhor este. Em algumas vezes os autores focam demais no uso de ferramentas extras, auxiliares ao desenvolvimento de aplicações ASP.NET MVC 2. Isso é bom para quando você já tem conhecimento e/ou vivência do framework.

Test-Drive ASP.NET MVC

Test-Drive ASP.NET MVC

Jonathan McCracken
The Pragmatic Programmers
June 2010

Regular

Eu esperava bem mais desse livro por se tratar de TDD. Havia imaginado vários passos práticos de desenvolvimento orientado a testes no melhor estilo Kent Beck ou Uncle Bob. Para quem já conhece TDD, não irá ver grandes novidades.

Eu uso o Shelfari como prateleira virtual para organizar os livros que li, estou lendo e pretendo ler.
É bem legal e tem vários recursos. Por exemplo, esse endereço lista os livros que li no ano de 2010.

.NET, Arquitetura, JavaScript, Livros, Ruby, TDD , , , , , , , , , , , ,

Melhores posts do ano de 2010

31 de dezembro de 2010

Como testar gravação de log em Ruby on Rails

17 de novembro de 2010

Em uma aplicação Ruby on Rails, quando você precisa assegurar nos seus testes que a gravação de logs está sendo realizada com sucesso, não há a necessidade de abrir o arquivo físico de log, ler seu conteúdo e verificar se a informação que você deseja está lá.

Ao invés disso, você pode substituir a saída de escrita padrão do log por outra classe de stream, como a StringIO, onde você terá fácil acesso ao que for gravado no log durante o teste.

Log em inglês também é tronco, lenha.

Log em inglês também é tronco, lenha.

Vamos ver um exemplo utilizando RSpec para testar a gravação de log de um método chamado do_something em uma classe modelo SomeModel.

require 'spec_helper'

describe SomeModel do
  before(:each) do
    @some_model = SomeModel.new

    @log_stream = StringIO.new
    @some_model.stub(:logger).and_return(Logger.new(@log_stream))
  end

  describe "#do_something" do
    it "logs info" do
      @some_model.do_something
      @log_stream.string.should include("I am logging something")
    end
  end
end

Na linha 7, criamos uma instância de StringIO atribuindo à variável @log_stream. É nesse objeto que serão gravados todos os logs do nosso teste. Para isso, na linha 8, substituímos o logger original por um stub de Logger que faz referência à instância da classe StringIO que criamos.

Já na linha 14, a asserção do nosso teste verifica se o texto correto foi gravado no stream do log. O método StringIO#string retorna a string bruta, ou seja, o texto que foi gravado no stream.

A seguir está a implementação do método do_something:

class SomeModel < ActiveRecord::Base
  def do_something
    # some implementation

    logger.info "I am logging something"
  end
end

Para fazer testes de gravação de logs em controllers, a idéia é a mesma, basta apenas usar o stub no método logger do controller (linha 6):

require 'spec_helper'

describe SomeModelsController do
  before(:each) do
    @log_stream = StringIO.new
    controller.stub(:logger).and_return(Logger.new(@log_stream))
  end

  describe "GET index" do
    it "logs info" do
      get :index
      @log_stream.string.should include("Now logging in a controller")
    end
  end
end
class SomeModelsController < ApplicationController
  def index
    # implementation

    logger.info "Now logging in a controller"
  end
end

Se você precisa usar log em uma classe que não seja um modelo ou controller, não vai poder chamar o método logger diretamente. Por exemplo, a classe a seguir, foi criada dentro da pasta lib de uma aplicação Rails.

class CoolClass
  def cool_method
    logger.info "Cool log!"
  end
end

Chamando o método cool_method teremos o seguinte erro:
> c = CoolClass.new
> c.cool_method
NameError: undefined local variable or method `logger’ for #<CoolClass:0×1e81bf0>

Resolver isso é simples, basta utilizar Rails.logger:

class CoolClass
  def cool_method
    Rails.logger.info "Cool log!"
  end
end

E no teste para gravação de log o stub é feito na classe Rails (linha 8):

require 'spec_helper'

describe CoolClass do
  before(:each) do
    @cool_class = CoolClass.new

    @log_stream = StringIO.new
    Rails.stub(:logger).and_return(Logger.new(@log_stream))
  end

  describe "#cool_method" do
    it "logs info" do
      @cool_class.cool_method
      @log_stream.string.should include("Cool log!")
    end
  end
end

Ruby, TDD , , , , ,

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 , , ,

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 , , , ,