So, you want to know how to get emails from GMail to manipulate in your Rails app right?

First let’s create our app and generate our main class:

$ rails app
$ cd app
$ script/generate scaffold task name:string description:text
$ rake db:migrate
$ rm -rf public/index.html

Map the tasks index action to be the root of the app:

#config/routes.rb
ActionController::Routing::Routes.draw do |map|
  map.resources :tasks
 
  map.root :tasks
end

At this point we have a working very simple app to manage our tasks list. Let’s start our server:

$ script/server

You can go to http://localhost:3000 and see our app running.
Now, create the mailer that will check gmail for us:

$ script/generate mailer MailReader

Edit the generated mailer to look like the above:

# app/models/mail_reader.rb
require 'net/pop'
 
class MailReader < ActionMailer::Base
  def receive(email)
    task = Task.new :name => email.subject, :description => email.body
    if email.has_attachments?
      email.attachments.each do |attachment|
        task.assets.create :data => attachment
      end
    end
  end
 
  def self.check_mail
    logger = RAILS_DEFAULT_LOGGER
 
    logger.info "Checking for emails..."
    Net::POP3.enable_ssl(OpenSSL::SSL::VERIFY_NONE) #This line raises error if ruby version &lt; 1.8.7
    Net::POP3.start("pop.gmail.com", 995, "your-email@gmail.com", "your-password") do |pop|
      if pop.mails.empty?
        logger.info "No emails found."
      else
        pop.mails.each do |email|
          begin
            logger.info "Retrieving mail..."
            MailReader.receive(email.pop)
            email.delete
          rescue Exception => e
            logger.error "[" + Time.now.to_s + "] " + e.message
          end
        end
      end
    end
    logger.info "Done."
  end
end

Note that your ruby version need to be 1.8.7 or higher.
Now we need to create our model that will keep the attachments and install the paperclip plugin:

$ script/plugin install git://github.com/thoughtbot/paperclip.git
$ script/generate model asset

Put this in the migration file:

# db/migrate/20090303181609_create_assets.rb
class CreateAssets < ActiveRecord::Migration
  def self.up
    create_table :assets do |t|
      t.string      :data_file_name
      t.string      :data_content_type
      t.integer     :data_file_size
      t.datetime    :data_updated_at
      t.references  :task
      t.timestamps
    end
  end
 
  def self.down
    drop_table :assets
  end
end

Run the migration:

$ rake db:migrate

Create the associations in the models:

# app/models/asset.rb
class Asset < ActiveRecord::Base
  belongs_to :task
 
  has_attached_file :data
end
# app/models/task.rb
class Task < ActiveRecord::Base
  has_many :assets
end

…and finally, modify the task show template to show the attachments:

  <!-- app/views/tasks/show.html.erb -->
 
  <b>Name:</b>
  <%=h @task.name %>
 
  <b>Description:</b>
  <%=h @task.description %>
 
  <% unless @task.assets.blank? -%>
 
  <b>Attachments:</b>
  <% @task.assets.each do |asset| -%>
    <%= link_to "Download \"#{asset.data_file_name}\"", asset.data.url %>
  <% end -%>
 
<% end -%>
 
<%= link_to 'Edit', edit_task_path(@task) %> |
<%= link_to 'Back', tasks_path %>

You can set up a cron job to check if there are new emails every two minutes by putting this your crontab file:

##__email_checker__
*/2 * * * * RAILS_ENV=production /usr/local/bin/ruby /home/mauricio/pdn-posts/how-to-pull-emails-from-gmail-to-rachments/app/script/runner MailReader.check_mail

And last but not least, the source code used for this post is hosted on github.

While I’m working, I always have a minimum of 3 or 4 open terminals: one for watching the logs, one for ssh and so on.
It’s not good to have a lot of windows open, and tab switching can be a pain, specially when you want to see what’s going on in one window while you type in another one.
So I’ve found recently Terminator.
Taken from terminator’s home page:

The goal of this project is to produce a useful tool for arranging terminals.
It is inspired by programs such as gnome-multi-term, quadkonsole, etc. in that the main focus is arranging terminals in grids (tabs is the most common default method, which Terminator also supports).

Much of the behaviour of Terminator is based on GNOME Terminal, and we are adding more features from that as time goes by, but we also want to extend out in different directions with useful features for sysadmins and other users. If you have any suggestions, please file wishlist bugs! (see below for the address)

Features:

* Arrange terminals in a grid
* Tabs
* Drag and drop re-ordering of terminals
* Lots of keyboard shortcuts
* Config file to override gnome-terminal settings
* Simultaneous typing to arbitrary groups of terminals

My screen.

My screen.

You can put your default configurations in the file ~/.config/terminator/config
Mine configurations are this:

#/home/mauricio/.config/terminator/config
enable_real_transparency=True
force_no_bell=True
scrollbar_position=disabled
titlebars=False
handle_size=1

This increased a lot my productivity. Unfortunately I haven’t found anything like Terminator for Mac.

Update (26/01): I’m using IDs on the feeds now, as I was getting duplicated feed entries. I followed this post written by Carlos Brando.


I had some trouble recently with atom feeds. I made it work with most the readers around there, but it took some time until I found why it isn’t working with Google Reader.
So, I’ll try to save some people time here.

First, you need a action for creating the feeds (could be the index action too, you just need to add the format.atom line):

# app/controllers/stories_controller.rb
def feed
    @project = Project.find(params[:project_id])
    @type = @project.types.find(params[:type_id])
    @stories = @type.stories(:order => 'updated_at desc')
 
    respond_to do |format|
      format.atom
    end
  end

Now, you need a builder for that action:

# app/views/stories/feed.atom.builder
atom_feed do |feed|
  feed.title("#{@project.name}->#{@type.name}")
  feed.updated(@stories.first.updated_at.strftime("%Y-%m-%dT%H:%M:%SZ"))
 
  for story in @stories
    next if story.updated_at.blank?
    feed.entry([@project, @type, story]) do |entry|
      entry.title(story.headline)
      entry.content(story.text, :type => 'html')
      entry.updated(story.updated_at.strftime("%Y-%m-%dT%H:%M:%SZ")) # needed to work with Google Reader.
      entry.author do |author|
        author.name(story.author)
      end
    end
  end
end

And finally, a route to the feed:

map.connect '/projects/:project_id/types/:type_id/feed', :controller => 'stories', :action => 'feed', :format => 'atom'

Now you can check if it’s valid with the Feed Validator.

The problem why it isn’t working with Google Reader was that I forgot the entry.updated line. Also, you need to format the time as it is above, so it’ll follow the rules for dates in the atom specification and will work with Google Reader.

Estava procurando uma forma de escrever no twitter de forma rápida e sem precisar abrir nenhum cliente, nem mesmo o site. Foi quando uma pergunta rápida ao guru me trouxe esse artigo.
Fiz algumas modificações (não conseguia postar mensagems com !) e acabei com esse script:

#!/usr/bin/ruby
`curl --basic --user "<myusername>:<mysecretpassword>" --data-ascii "status=#{ARGV.join(" ")}" "http://twitter.com/statuses/update.json"`

Substitua e com seu usuário e sua senha, salve o arquivo com o nome de twit em /usr/bin ou qualquer pasta no seu path, de permissão de execução (chmod +x /usr/bin/twit) e execute:

$ twit Estou postando a partir da linha de comando!

Se essa dica foi útil à você, poste nos comentários. :)

Fiquei um longo período sem postar nada. A coisa está corrida por aqui. Estou fazendo o deployment da minha aplicação, refatorando pedaços de código, corrigindo bugs, enfim, aparando as últimas arestas antes de colocar no ar.
Assim sendo, vamos com uma dica rápida para facilitar o acesso aos recursos de internacionalização inseridos no Rails 2.2.

Até o Rails 2.1 eu usava o Brazilian Rails para a formatação de datas, moeda, etc. Resolvi que era hora de tentar o I18n do Rails 2.2.

Primeiro passo: criar o locale ‘pt-BR.yml’ dentro de config/locales/:

time:
    formats:
      default: "%A, %d de %B de %Y, %H:%M"
      short: "%d/%m, %H:%M"
      long: "%A, %d de %B de %Y, %H:%M"
      hour: "%H:%M"
    am: ''
    pm: ''

no config/environment.rb:

I18n.default_locale = "pt-BR"

e vualá:

>> I18n.localize(Time.now)
=> "Segunda, 08 de Dezembro de 2008, 17:00"
>> I18n.localize(Time.now, :format => :short)
=> "08/12, 17:00"

Muito bem. Tudo funcionando. Mas é muito chato ter que chamar a classe I18n todo o tempo. Então vamos usar o poder de DSLs que Ruby nos dá.
Crie um arquivo em config/initalizers com o nome que preferir e adicione:

class Time
  def localize(options={})
    I18n.localize(self, options)
  end
end

Agora ficou muito mais fácil e intuitivo:

>> Time.now.localize
=> "Segunda, 08 de Dezembro de 2008, 17:04"
>> Time.now.localize :format => :short
=> "08/12, 17:04"

Isso pode ser feito similarmente com outros métodos, de outras classes também. Fica para o próximo post.

JRuby 1.1.4 vs Ruby 1.8 no Rails 2.2

Continuando a série de benchmarks começada ao comparar o Rails 2.1 com o Rails 2.2 em cima do Ruby 1.8, agora é a vez de comparar o JRuby e Ruby.
Se você não leu a explicação das diferenças do modelo de threading entre Ruby 1.8, Ruby 1.9 e JRuby, leia antes de prosseguir.
Estou rodando os testes no meu computador pessoal, que é um Pentium 4 3.0 HT, com 1Gb de memória rodando Ubuntu Linux. Já é um PC um tanto quanto ultrapassado, portanto o tempo de resposta acaba sendo um pouco alto, além de que ao mesmo tempo em que rodam os testes rodam também outros programas, como o Firefox por exemplo.
Vamos ao que interessa:

Ruby 1.8

$ ruby script/server -p 3001 -e production
$ ab -n 50 -c 5 http://localhost:3000/
 
Concurrency Level:      5
Time taken for tests:   3.903964 seconds
Complete requests:      50
Failed requests:        0
Write errors:           0
Total transferred:      573554 bytes
HTML transferred:       547350 bytes
Requests per second:    12.81 [#/sec] (mean)
Time per request:       390.396 [ms] (mean)
Time per request:       78.079 [ms] (mean, across all concurrent requests)
Transfer rate:          143.44 [Kbytes/sec] received

JRuby 1.1.4

$ jruby -J-Djruby.objectspace.enabled=false -J-Xmn128m -J-Xms512m -J-Xmx512m -J-server -J-Djruby.thread.pooling=true script/server -e production
$ ab -n 50 -c 5 http://localhost:3000/
 
Concurrency Level:      5
Time taken for tests:   7.976448 seconds
Complete requests:      50
Failed requests:        0
Write errors:           0
Total transferred:      573600 bytes
HTML transferred:       547350 bytes
Requests per second:    6.27 [#/sec] (mean)
Time per request:       797.645 [ms] (mean)
Time per request:       159.529 [ms] (mean, across all concurrent requests)
Transfer rate:          70.21 [Kbytes/sec] received

Mesmo utilizando todas as flags de performance tunning da wiki do JRuby, ele ainda se mostrou mais lento. Isso significa que o JRuby não vai tirar proveito do threadsafeting do Rails 2.2? Não!
Pelo que eu entendi pesquisando brevemente, ainda é preciso fazer alterações no código do JRuby pra que ele ofereça a melhor performance possível. Mesmo a última barreira para que o Rails possa ser executado em modo multi-threaded tenha sido removida, ainda é preciso implementar essa função no core do JRuby. Me corrijam se eu estiver errado.

Tempo de carga de uma única requisição no JRuby:

Processing IndexController#index (for 127.0.0.1 at 2008-10-30 18:44:58) [GET]
Completed in 186ms (View: 116, DB: 7) | 200 OK [http://localhost/]

…e no Ruby:

Processing IndexController#index (for 127.0.0.1 at 2008-10-30 18:45:13) [GET]
Completed in 131ms (View: 60, DB: 20) | 200 OK [http://localhost/]

O Ruby é 2x mais rápido que o JRuby ao renderizar a view, mas quase 3x mais lento em consultas ao banco.
Alguém já brincou com o JRuby e Rails 2.2? Obteve resultados melhores? Comentem.

No post passado eu falei sobre os benefícios do Rails 2.2 em termos de performance que obtive na minha aplicação. Porém, não deixei bem claro que a intenção dos meus testes eram comparar a diferença entre as duas versões do Rails apenas, sem tocar no interpretador Ruby. Então pra deixar as coisas mais claras, vou analizar aqui as diferenças entre os interpretadores Ruby 1.8 (MRI), Ruby 1.9 (YARV) e JRuby (JVM).

Ruby 1.8

É o Ruby estável atual. Suporta apenas Green Threads.
Isso significa que, não importa quantas threads você rode no seu programa, haverá apenas uma Thread alocada no kernel do sistema operacional. O efeito colateral disso é a necessidade de esperar que uma Thread termine a sua execução para começar outra Thread.
Até pouco tempo a solução para esse problema eram clusters de servidores. Com vários servidores rodando, cada um fica responsável por uma requisição, permitindo a execução de mais de um processo ao mesmo tempo (não concorrente). Mas gerava um outro problema: cada servidor precisava carregar na memória todas as bibliotecas, classes do framework, classes da aplicação, etc, o que gera um overload de memória.
Então chegaram os Phusion Guys com o Passenger e o Ruby Enterprise Edition, que juntos otimizaram esse processo. O que o Ruby Enterprise Edition fez foi compartilhar os objetos iguais entre as instâncias de Rails, diminuindo o overload. Contúdo você ainda tem conexões de banco, código de aplicação e dados em memória criados depois da inicialização duplicados.

Ruby 1.9

O Ruby 1.9 implementa o YARV (desenvolvido pelo Matz assim como o MRI) como virtual machine, o qual suporta Native Threads. Isso significa que cada Thread Ruby terá sua própria Thread no kernel do sistema operacional. Porém, isso não significa que haverá paralelismo entre as execuções das Threads. Somente um processo rodará por vez, independente de quantos cores tenha o servidor. Isso acontece devido ao GIL (Global Interpreter Lock), que também está presente no MRI.
O GIL nada mais é que uma trava gerada quando são solicitados processos de IO, para impedir que seja compartilhado código que não é Thread Safe entre as Threads.
Remover o GIL beneficiaria a utilização de mais de 1 core no servidor, pois possibilitaria a execução paralela de Threads. O problema é que muitas extensões feitas em C precisariam ser reescritas, o que atrasaria o lançamento. Talvez isso esteja nos planos para a versão 2.0.

JRuby

O JRuby usa JVM, a máquina virtual Java, e que suporta Native Threads e execução simultânea.
Isso significa dizer que várias requisições poderão ser executadas paralelamente, dependendo únicamente da quantidade de cores do seu servidor.

Então por que houve melhora na performance sem trocar o interpretador?

O que acontecia com o Rails até a versão 2.1.1 é que havia um lock único sobre cada requisição, e que fora substituido na versão 2.2 por locks menores, sobre os recursos compartilhados apenas. Porém, ao meu ver, mais importante que isso para a melhora de performance é o pool de conexões. Na versão 2.2, você pode configurar um pool de conexões com o banco de dados que serão acessados ao mesmo tempo.
No seu blog o Carlos Brando explicou como o pool de conexões funciona. Vale o acesso.

Hoje resolvi testar a minha aplicação de várias formas, pra ver se a nova versão do Rails traria algum benefício de fato para mim.

Primeiro rodei o Apache Benchmark na aplicação do jeito que ela estava, como Rails 2.1.1:

$ ab -n 50 -c 5 http://localhost:3000/
 
Concurrency Level:      5
Time taken for tests:   39.938685 seconds
Complete requests:      50
Failed requests:        0
Write errors:           0
Total transferred:      1036850 bytes
HTML transferred:       1010700 bytes
Requests per second:    1.25 [#/sec] (mean)
Time per request:       3993.869 [ms] (mean)
Time per request:       798.774 [ms] (mean, across all concurrent requests)
Transfer rate:          25.34 [Kbytes/sec] received

Hummm.. lento.. muito lento. Já estava preocupado com a hora de colocar isso em produção.

Atualizando o Rails para a versão 2.2 e rodando o benchmark:

$ ab -n 50 -c 5 http://localhost:3000/
 
Concurrency Level:      5
Time taken for tests:   32.228686 seconds
Complete requests:      50
Failed requests:        0
Write errors:           0
Total transferred:      590650 bytes
HTML transferred:       564400 bytes
Requests per second:    1.55 [#/sec] (mean)
Time per request:       3222.869 [ms] (mean)
Time per request:       644.574 [ms] (mean, across all concurrent requests)
Transfer rate:          17.87 [Kbytes/sec] received

What?? Cadê a melhora de performance? Rails não é Threadsafe agora?
É! Mas você tem que habilitar o recurso nas configurações pequeno Padawan:

No seu arquivo config/development.rb adicione no final:

config.threadsafe!

Rodando o Benchmark:

$ ab -n 50 -c 5 http://localhost:3000/
 
Concurrency Level:      5
Time taken for tests:   6.807438 seconds
Complete requests:      50
Failed requests:        0
Write errors:           0
Total transferred:      590620 bytes
HTML transferred:       564400 bytes
Requests per second:    7.34 [#/sec] (mean)
Time per request:       680.744 [ms] (mean)
Time per request:       136.149 [ms] (mean, across all concurrent requests)
Transfer rate:          84.61 [Kbytes/sec] received

Muito melhor não?! Uma melhora de quase 500%! Mas e se rodassemos em modo de produção?

$ ab -n 50 -c 5 http://localhost:3000/
 
Concurrency Level:      5
Time taken for tests:   3.693437 seconds
Complete requests:      50
Failed requests:        0
Write errors:           0
Total transferred:      573555 bytes
HTML transferred:       547350 bytes
Requests per second:    13.54 [#/sec] (mean)
Time per request:       369.344 [ms] (mean)
Time per request:       73.869 [ms] (mean, across all concurrent requests)
Transfer rate:          151.62 [Kbytes/sec] received

Impressionado pequeno Padawan? Cuidado! Nada disso aqui significa que sua aplicação vai ficar tão melhor quanto a minha somente com a nova versão do Rails. A aplicação em questão aqui envolve muitos cálculos complexos, e por isso tira vantagem do threading.
Tentei fazer alguns testes com o mysqlplus, driver de mysql pra ruby que promete acesso assíncrono ao banco de dados. O tutorial que eu segui simplesmente não funcionou no meu ambiente. Li em algum dos posts que pesquisei que eles estavam concentrando esforços pra fazer funcionar com o Rails 2.2 e corrigir alguns bugs.
Rails escala? Pra minha aplicação sim. E pra sua?

GTBox - Controle de caixa

UPDATE (03/11/08): Salvando apropriadamente agora. O problema era que eu mandava o Gazpacho salvar meus campos como String no data-type, mas ele não salvava nada. Solução: abra os arquivos salvos com o gazpacho em um editor de texto qualquer e sete a opção data-type como str, int ou whatever.



A avaliação de uma das matérias do meu curso é a construção de um sistema em Python ou em Java que se comunique com o banco de dados. Muito simples mesmo.

Então comecei um projetinho usando Python + Kiwi + SQLObject+ Gazpacho, que na breve pesquisa que eu fiz acreditei ser a melhor opção. Mas aí me deparei com um grande problema: a falta de documentação do Kiwi. Vários probleminhas que concerteza são muito simples, mas que sem nenhuma referência são difíceis de resolver apareceram.

Tudo está aparentemente certo. Mas quando eu mando salvar as alterações para o banco, todos os campos são salvos como Null.

Pra quem quiser dar uma olhada no projeto ou até mesmo contribuir eu o coloquei no github:

git clone git://github.com/mauriciozaffari/gtbox.git

A intenção não é de forma alguma fazer algo muito sofisticado e qualquer ajuda será muito bem vinda.

Semana passada tivemos o Rails Summit, primeiro grande evento de Rails no Brasil. O Ozéias organizou uma van para levar o pessoal do Paraná, e uns perdidos de Santa Catarina também, e eu embarquei nessa.

Galera da Van

Galera da Van

Foram 13 horas de viagem não muito confortável, mas também não insuportável. Não fosse alguém que não parava de falar um minuto a viagem teria sido menos cansativa. Chegamos antes das 7 horas da manhã e fomos direto para o evento, nem aberto tava ainda. Fomos os primeiros a chegar!

Primeiros a Chegar

Chegamos pra abrir as portas do evento

A organização estava ótima! Desde a organização das palestras aos coffee breaks e almoços. Parabéns ao Fabio Akita e para todo o pessoal da Locaweb que se esforçaram muito para fazer desse um evento muito bom.

As palestras foram muito boas mesmo, mas o ponto alto do evento foi conhecer o pessoal. Nerds de todos os tipos estavam presentes.. nunca vi tanto MacBook no mesmo lugar. Conheci muita gente legal, mas ao mesmo tempo não tive tempo de conhecer melhor muita gente. A galera twittou o tempo inteiro, foi aberto um canal no irc e até foi criado um belo projeto no github! Graças ao livestream do BlogBlogs foi possível acompanhar tudo que era comentado sobre o evento em vários serviços.

Um dos clones do Dr. Nic estava presente

Um dos clones do Dr. Nic estava presente

Nesse evento foi possível ver como a comunidade ruby é uma comunidade unida. O pessoal sempre prestativo e atencioso, até nos FAILcasts da vida! Ao pessoal que não pôde estar presente, dêem um jeito de aparecer ano que vêm. Satisfação garantida ou seu dinheiro de volta.