While we are waiting for the next release of rack that will come with that fix, I extract a code from a pull request in rack repository and created a monkey patch to fix this problem.

This problem often happens when you are using google analytics or another service

https://gist.github.com/2896202

Esse é o primeiro post de uma séria voltada para como melhorar o desempenho de seu site/sistema web. Hoje em dia, trabalhar com desenvolvimento web envolve vários fatores. Um deles é o desempenho, desenvolver um sistema/site que tenha uma performance boa também envolve diversos aspectos. Existem algumas extensões para o firefox capaz de testar o desempenho da sua camada de visão, são eles o yslow do Yahoo! e o Page Speed do Google. Ambos tem basicamente as mesmas funcionalidades, que no geral se resume a testar a performance da sua camada de visão e lhe dá dicas de como melhora-las. Ele lhe avisa, por exemplo, quando você tem uma imagem grande e está reduzindo sua visualização no html ou css. Dentre outras coisas, tais como: habilitar a compressão GZIP, diminuir o tamanho dos cookies, habilitar o cache para determinadas áreas/arquivos. Enfim, é uma extensão super simples de usar e que não pode faltar a um Desenvolvedor web.

Olá pessoa, sei que o blog anda meio parado. Os últimos 3 meses foram de muita correria, fui promovido no trabalho, assumindo o cargo de gerente do setor de desenvolvimento, o que tomou grande parte do meu tempo. Oxente Rails Fazendo um resumo dos últimos meses, em agosto estive em natal, no OxenteRails. Um evento de muita qualidade, recomendo a todos, em 2011 estarei lá novamente. Agradecimento ao meu grande amigo Karlisson que ofereceu hospedagem.

Software Freedom Day 2010

Em Setembro, estive em Campina Grande (cidade maravilhosa que espero ter o prazer de conhecer melhor) para palestrar no Software Freedom Day 2010 sobre Ruby On Rails e Desenvolvimento Ágil. Em breve estarei postando os slides da palestra aqui. Infelizmente estava um pouco doente e não conseguir ficar até o final do evento (minha voz acabou no momento que terminei minha palestra). Espero está lá novamente em 2011. Atualmente Estou no momento mexendo um pouco com aplicativos de Web Mapping com Ruby On Rails, já havia mexido com Java e agora como tenho dedicado meu tempo somente a Rails, achei interessante começar a fuçar. Para quem tem interesse, existe uma excelente Gem chamada Spatial_Adapter, que auxilia o ActiveRecord a tratar os dados geográficos. Atualmente os Bancos suportados são: PostgreSQL (com sua extensão espacial Postgis) e o MySQL. E para quem quer utilizar o Google Maps para exibição dos mapas no seu aplicativo, também já existe uma Gem para isso, a google_maps. Resumindo é isso, tentarei postar pelo menos mensalmente no blog. Happy Hack ;-)

Nesse rápido post irei demonstrar como iniciar o desenvolvimento de uma aplicação com o Rails 2.3.8, utilizando como banco de dados NoSql o Mongodb. Para conexão com o banco, utilizaremos a gem Mongoid. Também iremos configurar para testes o Rspec e o Cucumber. Considerando a parti daqui que você tem todas as gems citadas anteriormente instaladas no seu ambiente. Primeiro começaremos criando uma aplicação Rails, nada de novo aqui. rails app_teste Com isso iremos gerar toda a estrutura da aplicação. Agora vamos configurar as gems utilizadas, em ‘config/enviroment.rb’, adicionaremos dentro do bloco ‘Rails::Initializer.run’ a gem do mongoid:

Rails::Initializer.run do |config|
  config.gem 'mongoid'
  config.time_zone = 'UTC'
end
Com a gem do Mongoid, não precisaremos mais do ActiveRecord, para remover de sua aplicação basta adicionar dentro do mesmo bloco que você configurou o a gem, a seguinte linha ‘config.frameworks -= [:active_record]’. Deixando meu enviroment.rb assim:
Rails::Initializer.run do |config|
  config.frameworks -= [:active_record]
  config.gem 'mongoid'
  config.time_zone = 'UTC'
end
Quando utilizavamos o ActiveRecord, por padrão ele procurava um arquivo YAML chamado database.yml no qual continha as informações sobre o meu banco. No caso do mongoid, podemos continuar com esse mesmo arquivo, ou criar outro (no meu caso eu prefiro criar um chamado mongoid.yml). Abaixo segue o meu arquivo yml:
base: &base
  adapter: mongodb
  # em tempo de execucao vamos adicionar o "-#{Rails.env}" ao nomo do banco
  database: "feedse"
# Se estiver rodando o mongodb em outro host,
#vc deveria autenticar-se
  #host: host.mongodb.com
  #username: your-username
  #password: your-password

# use as proximas linhas para colocar algo especifico a cada ambiente
development:
  <<: *base

test:
  <<: *base

production:
  <<: *base
Feito isso, agora precisamos que nossa aplicação leia esse arquivo e configure nossa conexão com o banco. Para isso, criaremos um arquivo chamado ‘mongo.rb’ (ou qualquer outro nome que você queira) dentro do diretório config/initializers. mongo.rb
require 'yaml'

mongo_config = YAML::load(File.read(File.join(Rails.root, 'config/mongoid.yml')))[Rails.env]

Mongoid.configure do |config|
  config.from_hash(mongo_config)
end

Com isso, já temos tudo pronto em relação ao nosso banco. Criaremos então, um model chamado ‘Content’. Lembrando que como não utilizamos mais o ActiveRecord, nossa classe não deverá herdar ActiveRecord::Base. Abaixo segue a implementação da nossa classe:
class Content
  include Mongoid::Document
  field :title, :type => String

  validates_presence_of :title
  validates_uniqueness_of :title
end
Para que nossa classe seja persistida em nossa banco, precisamos incluir o include Mongoid::Document. Precisamos também definir os campos que ele vai ter, no nosso caso somente o campo ‘title’. A definição básica dos campos segue a seguinte estrutura ‘field , :type => ’. Para mais informações consulte a documentação do mongoid. Utilizando o RSpec Vamos gerar a estrutura do rspec, como faríamos em qualquer outro projeto Rails. script/generate rspec Logo após gerar a estrutura, abra o arquivo spec_helper.rb dentro do diretório spec recém gerado, e dentro do bloco Spec::Runner.configure comente as seguinte linhas:
  config.use_transactional_fixtures = true
  config.use_instantiated_fixtures  = false
  config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
Um dos problemas que enfrentei logo quando comecei a mexer com Rspec junto com MongoDb, foi que o rpspec não limpa o banco de testes após executar os mesmos. Logo isso deverá ser feito na mão, para isso adicionaremos dentro do bloco Spec::Runner.configure em o seguinte código:
  config.after(:each) do
    Mongoid.database.collections.each do |collection|
      unless collection.name =~ /^system\./
        collection.remove
      end
    end
  end
Deixando o nosso spec_helper.rb assim:
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path(File.join(File.dirname(__FILE__),'..','config','environment'))
require 'spec/autorun'
require 'spec/rails'

# in ./support/ and its subdirectories.
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}

Spec::Runner.configure do |config|

  #config.use_transactional_fixtures = true
  #config.use_instantiated_fixtures  = false
  #config.fixture_path = RAILS_ROOT + '/spec/fixtures/'
  #clean database mongodb after tests
  config.after(:each) do
    Mongoid.database.collections.each do |collection|
      unless collection.name =~ /^system\./
        collection.remove
      end
    end
  end

end
Nesse caso o Rspec irá limpar o banco depois de cada teste ‘each’, mas você pode efetuar a limpeza somente depois de todos os testes terem rodado, nesse caso ao invés de ‘:each’ como parâmetro, utilizaremos ‘:suite’, e caso você queira executar alguma coisa antes dos testes, utilize o ‘config.before’, que funciona exatamente da mesma maneira do ‘config.after’, com a diferença de ser executado antes(before) dos testes. Obs: Se você está utilizando também o cucumber e está com problemas em relação a limpeza do banco após os testes, a solução é simples. Crie o arquivo ‘clean_mongo.rb’ (ou qualquer outro nome) dentro de features/support e adicione nele o código abaixo:
After do |scenario|
  Mongoid.database.collections.each do |collection|
    unless collection.name =~ /^system\./
      collection.remove
    end
  end
end
E com isso temos nossos testes funcionando com o mongodb.

Esse post é uma “continuação” do anterior, estarei demonstrando como fazer uma query no “like %” no MongoDb, utilizando a gem MongoMapper Como no post anterior, eu tenho o model “Person”:

class Person
  include MongoMapper::Document
  key :name, String
  key :middle_initial, String
end
E eu preciso encontrar todos os registros (no caso do Mongodb, documentos) que contenham o nome “Silva” em ‘name’, podendo ter vários Silva’s, como: “João da Silva”, “Maria Silva” e etc… A solução, mais uma vez, é simples:
Person.all("$where" => "function() { return this.name.match(/"Silva"/i)"})

Comecei semana passada a utilizar o Mongodb (utilizando a biblioteca mongoid) em um novo projeto que estou desenvolvendo. Embora a documentação do Mongoid seja excelente, tive problemas para utilizar uma query com o ‘like %%’ de pesquisa como eu utilizava em bancos de dados relacionais. A solução que eu encontrei foi utilizar uma Regex no parâmetro de busca. Imagine que eu tenho um model chamado Person, como o abaixo:

class Person
  include Mongoid::Document
  field :name
  field :middle_initial
end
E eu preciso encontrar todos os registros (no caso do Mongodb, documentos) que contenham o nome “Silva” em ‘name’, podendo ter vários Silva’s, como: “João da Silva”, “Maria Silva” e etc… A solução é simples:
Person.find(:all, :conditions => {:name => Regexp.new("Silva")}).entries
Então será retornado um array contendo todos os documentos com o termo “Silva” no nome.

O is_paranoid é uma gem que faz com que os registros do banco não sejam apagados através do método destroy. Ao chamar o método destroy nosso objeto é apenas marcado como apagado e pode ser restaurado posteriormente, bem como listado através de método fornecidos pelo is_paranoid. Sua utilização é bem simples, primeiro instale a gem:

gem install is_paranoid

Para que funcione em sua aplicação Rails, adicione no enviroment.rb , dentro do bloco de inicialização:
config.gem "is_paranoid"
Deixando mais ou menos assim:
Rails::Initializer.run do |config|
  # ...
  config.gem "is_paranoid"
end
Agora, nos models que vão utilizar dos recursos do is_paranoid, adicione logo após a declaração da classe ‘is_paranoid’ Exemplo:
class Student < ActiveRecord::Base
  is_paranoid
end
E para finalizar, crie uma migrate que adicione na tabela que vai utilizar o is_paranoid, o campo ‘deleted_at’, do tipo ‘timestamp’. Exemplo:
class AddIsparanoidInStudent < ActiveRecord::Migration
  def self.up
    add_column :students, :deleted_at, :timestamp
  end

  def self.down
    remove_column :students, :deleted_at
  end
end
Pronto! Se quiser saber mais sobre o is_paranoid, consulte a documentação oficial no site do projeto.

O restful_authentication é um plugin de autenticação para aplicativos ruby on rails, com excelentes recursos, super fácil de configurar. Enfim, não vou falar muito sobre ele, pois não é o propósito desse tutorial. Irei assumir que você já tem o restful_authentication funcionando e quer apenas adicionar a funcionalidade de enviar um código de reset password via email para o usuário que esqueceu sua senha. Ao acessar o link com esse código o sistema irá exibir uma tela de troca de senha, lembrando que esse código deverá ser único e poderá ser usado somente uma vez. Então vamos lá: Primeiro iremos gerar uma migration que adiciona na tabela o usuário a coluna ‘reset_password_code’. script/generate migration reset_password_code Agora editarei a migration gerada, deixando da seguinte forma:

class ResetPasswordCode < ActiveRecord::Migration
  def self.up
    add_column :users, :reset_password_code, :string
  end

  def self.down
    remove_column :users, :reset_password_code
  end
end
em seguida, ‘rake db:migration’ e estaremos pronto para começar! Na classe UsersController irei criar um método protected que irá gerar um código para ser enviado ao usuário.
protected
  def random_code( len = 40 )
    chars = (("a".."z").to_a + ("1".."9").to_a )- %w(i o 0 1 l 0)
    newpass = Array.new(len, '').collect{chars[rand(chars.size)]}.join
  end
Agora criarei o método que chamará a view com o campo para o usuário colocar seu email:
  def change_reset_password
  end
Agora criarei a view que receberá o endereço de email do usuário e chamará o método “reset_password” passando o email:
<p>
    <%= form_tag (:controller => 'users', :action => 'reset_password' ) %>

    <p>
        <%= label_tag 'Email' %>
        <br/>
        <%= text_field_tag (:email) %>
    </p>
    <p>
        <%= submit_tag 'Enviar' %>
    </p>
    <%= flash[:alert] %>
</p>
Já método reset_password, irá receber o email, procurar o usuário com esse email, gerar o código de reset password, e chamar o UserMailer para enviar o email com o código.
  def reset_password
    user = User.find_by_email(params[:email])
    unless user.nil?
      user.reset_password_code = random_code
      if user.save!
        UserMailer.deliver_new_password(user)
        flash[:done] = "Verifique seu email para trocar a senha"
        redirect_to ('/')
      else
        flash[:error] = "Erro ao efetuar trocar de senha"
        render :action => 'change_reset_password'
      end
    else
      flash[:error]  = "Email Inválido"
      render :action => 'change_reset_password'
    end
  end
Vejam que estou chamando “UserMailer.deliver_new_password(user)” e passando o usuário como parâmetro. Na classe ‘UserMailer’ devo criar o método ‘new_password’ que será usado para enviar o email. Meu método new_password deverá ficar assim:
  def new_password(user)
    setup_email(user)
    @subject    += 'Mudança de senha'
    @body[:url]  = "#{$SERVER_CONTENT_BASE}/password/#{user.reset_password_code}"
  end
Agora criarei a view para esse email, dentro de ‘app/views/user_mailer’ com o nome de ‘new_password.html.erb’
Olá <%=h @user.login %> alguém solicitou a troca de senha para essa conta. 
Se deseja realmente trocar sua senha, clique no link abaixo:
<%=h @url %>
Agora de volta ao UsersController, criarei o método que recebe o reset_code e se ele estiver correto será jogado em um campo hidden na view de troca de senha.
  def code_password_reset
    user = User.find_by_reset_password_code(params[:reset_code])
    if user.nil?
      flash[:error]  = "Código inválido"
      redirect_to ('/')
    else
      @reset_code = params[:reset_code]
      render :action => "new_password"
    end
  end
Criarei a view de troca de senha, chamada ‘new_password’
<p>
    <%= form_tag (:controller => 'users', :action => 'reset_password_update', :method => 'put' ) %>
    <p>
        <%= label_tag 'Nova Senha' %>
        <br/>
        <%= password_field_tag (:password) %>
    </p>
    <p>
        <%= label_tag 'Confirmação' %>
        <br/>
        <%= password_field_tag (:password_confirmation) %>
    </p>
    <%= hidden_field_tag(:reset_code, @reset_code) %>
    <p>
        <%= submit_tag 'Enviar' %>
    </p>
	<%= flash[:alert]%>
</p>
E agora o método que de fato executa a troca de senha:
  def reset_password_update
    @user = User.find_by_reset_password_code(params[:reset_code]) unless params[:reset_code].blank?
    if ((params[:password] == params[:password_confirmation]) && !params[:password_confirmation].blank?)
       @user.password_confirmation = params[:password_confirmation]
       @user.password = params[:password]
       @user.reset_password_code = nil
      if @user.save!
        flash[:done] = "Senha atualizada com sucesso!"
        redirect_to ("/")
      else
        flash[:alert] = "Falha ao atualizar senha."
        render :action => 'new_password'
      end
    else
      flash[:alert] = "Senhas diferentes!"
      render :action => 'new_password'
   end
  end
Para finalizar iremos configurar as rotas;
  map.resources :users, :collection => { :change_reset_password => :get,
                                         :new_password => :get, :reset_password_update => :post,
                                         :code_password_reset => :get, :reset_password => :get}
  map.connect 'password/:reset_code', :controller => 'users', :action => 'code_password_reset'
E assim chegamos ao fim desse tutorial.

Essa semana comecei a utilizar o rspec para realizar testes na aplicação que estou trabalhando e estou gostando muito, pra não dizer que estou viciado. O Rspec torna o trabalho de escrever testes divertido, rápido e prático. Abaixo segue o link de alguns excelentes artigos que tive a chance de ler sobre rspec: http://blog.wolfman.com/articles/2007/7/6/rspec-testing-views-for-escaped-html http://www.elevatedrails.com/articles/2007/09/10/testing-controllers-with-rspec/
http://simplesideias.com.br/usando-o-rspec-para-testar-sua-aplicacao-rails-modelos/
http://simplesideias.com.br/7-coisas-que-voce-precisa-conhecer-no-rspec/
http://blog.davidchelimsky.net/2007/05/14/an-introduction-to-rspec-part-i/

Uma maneira fácil de se trabalhar com paginação no Ruby on Rails é utilizar o plugin will_paginate. Nesse breve artigo irei demonstrar como instalar e utilizar em sua aplicação. Primeiro instalaremos o plugin: gem install will_paginate Com o plugin instalado, podemos começar a configura-lo na aplicação. Para isso abra o arquivo environment.rb dentro do diretório config e adicione no final do arquivo a seguinte linha:

require "will_paginate"
Com isso, sua aplicação só irá subir se o plugin will_paginate estiver presente. Já no controlador devo usar o método paginate para efetuar a busca pelos registros no banco. No meu caso, tenho uma entidade chamada ‘noticia’ e no método ‘index’ do seu controlador, pelo padrão o rails faz uma busca por todos os registros no banco.
  def index
    @noticias = Noticia.all

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render : xml => @noticias }
    end
E no caso eu irei deixa-lo assim:
  def index
    @noticias = Noticia.paginate :page => params[:page], : order => 'created_at DESC', :per_page => 10

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render : xml => @noticias }
    end
  end

Onde o “:order =>” irá definir a ordem de exibição dos registros. E o “:per_page =>” a quantidade de registros por página. E pra terminar, abra a view e adicione logo abaixo do término da tabela:
<%= will_paginate @noticias %>