Archive for the ‘Ruby on Rails’ Category

Trânsito Não! Um experimento com Twitter, Trânsito e Ruby on Rails

Sunday, April 26th, 2009

O Twitter se tornou uma grande ferramenta para interação social, já até ameaçando o conteúdo oferecido em blogs.

Indo ainda mais longe, alguns já falam que não importa mais quantos seguidores você tenha no Twitter, mas que a pessoa com maior autoridade é aquela com o maior número de mensagens “retweetadas”, mostrando então que o que esta pessoa escreve é conteúdo bom e merece ser repassado a todos.

O projeto Trânsito Não! é um experimento social com Twitter e um assunto que deixa todo mundo fora de si: o trânsito. Este website conta tweets enviados como idéias e/ou votos, gerando um espaço público de discussão sobre um dos problemas mais urgentes destes dias.

Este projeto é direcionado a todo o Brasil, só que mais especialmente aquelas pessoas que vivem na Grande São Paulo, uma região com cerca de 17 milhões de habitantes que experimentam um dos maiores volumes de tráfego de veículos do mundo.

Usei Ruby on Rails para construir este site. Este framework web oferece grande produtividade ao desenvolvedor. Se você ainda não assistiu, não deixe de ver este vídeo que mostra a criação de um blog em apenas 15 minutos usando Ruby on Rails.

O sistema de votação funciona assim: você envia um tweet (no Twitter) com uma idéia ou solução para resolver o problema do trânsito. Esta idéia vira então uma “idéia” dentro do Trânsito Não! Cada retweet da sua idéia, vira um voto. Então quanto mais a sua idéia se espalhar no Twitter, mais votos ela recebe no site. Os tweets são obtidos do Twitter através de uma API que é lida a cada minuto. As idéias ou votos são adicionados ao banco de dados, e as páginas são geradas novamente.

Você pode me encontrar em meu blog, Twitter, ou por e-mail.

Transito Não! An experiment with Twitter, Traffic Jams and Ruby on Rails

Sunday, April 26th, 2009

Twitter has become a great tool for social interaction, and it’s also gaining more authority than content in blogs.

Going even further, some people say it doesn’t matter how many followers you have on Twitter, but instead what matters is how many times your tweets get forwarded by those following you, showing that this person writes more valuable content, which deserves to be sent over to other people.

The project Trânsito Não! (which stands for “No To Traffic!”) is a social experiment with Twitter and a subject that gets everyone mad: the traffic jams. This web app cast tweets as ideas and/or votes, generating a public web space to debate on one of the most urgent problems of these days.

This project is aimed at the Brazilian people, specially those people living in the greater area of Sao Paulo, a region with about 17 million people experiencing one of the biggest car traffics in the world.

I developed this website with Ruby on Rails. This web framework offers great productivity to the developer. If you haven’t the chance yet, don’t miss this video showing a complete web blog written in only 15 minutes using Ruby on Rails.

The voting works like this: you tweet some idea or solution for the traffic problems, followed by the hashtag #transitonao. This tweet becomes a “idea” on TransitoNao website. If your tweet gets retweeded X times, these X times become votes for your idea. So the longer your idea spreads, the more votes you get. New tweets are read from the Twitter API every minute, being added to the database, and the pages being also refreshed (using page caching).

You can find me on my blog, Twitter, or at my personal email.

Scaling Rails

Friday, February 6th, 2009

Gregg Pollack and New Relic just launched a Screencast series on Scaling Rails. And, it’s free! :)

“Scaling Rails Screencast Series” produced by Gregg Pollack and supported by New Relic.

“Learn everything you need to know about Scaling your Rails app through 13 informative Screencasts produced by Gregg Pollack with the support of New Relic. In the next few weeks we’re going to bring you 13 educational videos, teaching you just about everything you need to know to create a Rails application that can scale.”

Topics covered:

Tratando Múltiplos Models em Um Único Form

Tuesday, January 13th, 2009

O livro Advanced Rails Recipes é um livro muito interessante para quem quer aprender algumas dicas mais avançadas de Rails. Especialmente aquele tipo de dicas que você não encontra em tutoriais ou blogs por aí. Da descrição do site:

“Você irá aprender como os profissionais resolveram problemas complicados usando as técnicas mais atualizadas de Rails 2, para que você possa entregar a sua impressionante aplicação Web de forma mais fácil e mais rápida.”

Esta é uma tradução para o português, com autorização de Dave Thomas de Pragmatic Programers. Aproveite! :)

Tratando Múltiplos Models em Um Único Form

Por Ryan Bates (http://railscasts.com/). Ryan trabalha com desenvolvimento Web desde 1998. Começou a trabalhar profissionalmente com Ruby on Rails em 2005 e é mais conhecido pelo seu trabalho com os Railscasts, uma série gratuita de screencasts sobre Ruby on Rails.

Problema

A maioria do código Rails que você encontra geralmente trata um model de cada vez. Isso nem sempre é prático. Algumas vezes você precisa criar e/ou editar dois (ou mais) models em um único form, nas situações onde você tem uma associação one-to-many entre os models.

Solução

Digamos que nós precisamos salvar todas as tarefas pendentes para vários projetos. Quando nós criarmos ou atualizarmos um projeto, nós gostaríamos de adicionar, remover e atualizar suas tarefas, em um único form. O que estamos imaginando é:

Vamos começar criando um relacionamento has_many entre Project e Task. Para simplificar, vamos dar para cada model um atributo obrigatório chamado name.


# Arquivo: app/models/project.rb
class Project < ActiveRecord::Base
  has_many :tasks, :dependent => :destroy
  validates_presence_of :name
end

# Arquivo: app/models/task.rb
class Task < ActiveRecord::Base
  belongs_to :project
  validates_presence_of :name
end

Nós vamos usar a biblioteca de Javascript Prototype, então antes de qualquer coisa vamos garantir que ela está carregada em nosso arquivo de layout:


# Arquivo: app/views/layouts/application.html.erb
<%= javascript_include_tag :defaults %>

Vamos voltar a nossa atenção para o form, para criar um projeto com suas múltiplas tarefas, e associadas ao projeto. Quando precisamos tratar múltiplos models em um form, é muito útil eleger um model como sendo o foco primário ou principal, e a partir daí construir os models adicionais através da associação entre eles.

Neste caso, vamos fazer de Project o nosso model primário e construir suas tarefas através da associação has_many. Então para a action new de nosso ProjectsController, nós criamos um objeto Project da forma usual. No entanto, nós também inicializamos uma nova Task (em memória) que é associada com o Project de forma que nosso form tem alguma coisa para começar a trabalhar:


# Arquivo: app/controllers/projects_controller.rb
def new
  @project = Project.new
  @project.tasks.build
end

O template para o form precisa de algumas “manhas” já que nós precisamos tratar os campos para o model Project e também os campos de cada um dos models Task. Então, vamos quebrar o problema em partes menores e usar um partial para renderizar os campos da Task e adicionar um helper add_task_link para criar o link que adiciona uma nova tarefa:


# Arquivo: app/views/projects/_form.html.erb
<%= error_messages_for :project %>

<% form_for @project do |f| -%>
  <p>
  Name: <%= f.text_field :name %>
  </p>
  <div id="tasks">
    <%= render :partial => 'task', :collection => @project.tasks %>
  </div>
  <p>
    <%= add_task_link "Add a task" %>
  </p>
  <p>
    <%= f.submit "Submit" %>
  </p>
<% end -%>

Os templates new e edit simplesmente renderizam este partial de formulário, de forma que nós temos uma forma consistente para criar e atualizar um projeto. A partial do form vai e renderiza uma partial de tarefa para cada uma das tarefas do projeto. Antes de entrarmos no conteúdo da partial de tarefa, vamos dar uma olhada naquele helper add_task_link:


# Arquivo: app/helpers/projects_helper.rb
def add_task_link(name)
  link_to_function name do |page|
    page.insert_html :bottom, :tasks, :partial => 'task' , :object => Task.new
  end
end

Quando nós clicamos no link “Add a Task”, nós queremos um novo conjunto de campos de tarefas aparecendo abaixo dos campos de tarefa que já existem no formulário. Ao invés de ocupar o servidor com isto, nós podemos usar JavaScript para adicionar os campos dinamicamente. O método link_to_function aceita um bloco de código RJS. Geralmente nós associamos código RJS com chamadas assíncronas indo para o servidor. Mas neste caso o código RJS gera JavaScript que é executado no browser imediatamente quando o usuário clica no link. O resultado é que renderizar os campos para adicionar uma nova tarefa não requer uma requisição enviada ao servidor, o que leva a um tempo de resposta mais rápido no uso da aplicação.

Voltando ao partial do form, nós estamos usando form_for para dedicar o form para o model @project. Como então nós vamos adicionar campos para cada uma das tarefas do projeto? A resposta está dentro da partial de tarefa:


# Arquivo: app/views/projects/_task.html.erb
<div class="task">
<% new_or_existing = task.new_record? ? 'new' : 'existing' %>
<% prefix = "project[#{new_or_existing}_task_attributes][]" %>

<% fields_for prefix, task do |task_form| -%>
  <p>
    Task: <%= task_form.text_field :name %>
    <%= link_to_function "remove" , "$(this).up('.task').remove()" %>
  </p>
<% end -%>
</div>

O ingrediente chave aqui é o método fields_for. Ele se comporta de forma muito parecida com form_for mas ele não renderiza a tag HTML form. Isto nos permite mudar o contexto para um model diferente, no meio do form principal – como se nós estivéssemos embutindo um form dentro de outro.

O primeiro parâmetro para fields_for é muito importante. Esta string será usada como um prefixo para cada campo de tarefa. Como vamos usar esta partial também para renderizar tarefas existentes – e nós queremos mantê-las separadas quando o form é enviado – no prefixo nós incluímos uma indicação dizendo se a tarefa é nova ou existente. (O ideal seria criar esta string de prefixo em um helper, mas vamos simplificar um pouco as coisas aqui.)

O HTML gerado para uma nova tarefa se parece com isto:


<input name="project[new_task_attributes][][name]" size="30" type="text" />

Se esta fosse uma tarefa existente, o Rails iria colocar automaticamente o ID da tarefa entre as chaves, assim:


<input name="project[existing_task_attributes][7][name]" size="30" type="text" />

Agora, quando o form é enviado, o Rails irá decodificar o nome do campo de entrada, para forçar uma estrutura no hash params. As chaves ([]) que estão preenchidas se tornam keys em um hash aninhado. As chaves que estão vazias se tornam um array. Por exemplo, se nós enviarmos o form com duas novas tarefas, o hash params vai ficar assim:


"project" => {
  "name" => "Yard Work" ,
  "new_task_attributes" => [
    { "name" => "rake the leaves" },
    { "name" => "paint the fence" }
  ]
}

Note que os atributos para o projeto e cada tarefa estão aninhados dentro do hash project. Isto é conveniente porque significa que a action create em nosso controller pode simplesmente passar todos os atributos de projeto ao model Project sem se preocupar sobre o que está dentro do hash project:


# Arquivo: app/controllers/projects_controller.rb
def create
  @project = Project.new(params[:project])
  if @project.save
    flash[:notice] = "Successfully created project and tasks."
    redirect_to projects_path
  else
    render :action => 'new'
  end
end

Este código se parece com uma action create padrão, para um form de um único model. Mas existe algo sútil acontecendo aqui. Quando chamamos Project.new(params[:project]), o Active Record assume que nosso model Project tem um atributo correspondente chamado new_task_attributes porque ele procura uma key chamada new_task_attributes dentro do hash params[:project]. Isto é, o Active Record tentará fazer uma atribuição em massa (mass assign) de todos os dados contidos neste hash, para os atributos correspondentes no model Project. Mas nós não temos um atributo new_task_attributes em nosso model Project.

Um jeito conveniente de manter tudo isto transparente, da ponto de vista do controller, é usar um atributo virtual. Para fazer isso, nós simplesmente criamos um método setter em nosso model Project, chamado new_task_attributes=, que recebe um array e constrói a tarefa para cada elemento:


# Arquivo: app/models/project.rb
def new_task_attributes=(task_attributes)
  task_attributes.each do |attributes|
    tasks.build(attributes)
  end
end

Pode parecer que estas tarefas não estão sendo salvas em lugar nenhum. De fato, o Rails vai fazer isso automaticamente quando o projeto é salvo, porque ambos o projeto e suas tarefas associadas, são novos registros.

E isso é tudo que precisamos para criar um projeto. Vamos ver agora como atualizá-lo.

Assim como antes, nós precisamos de uma forma de adicionar e remover tarefas dinamicamente, mas desta vez se uma tarefa já existe, ela deve ser atualizada. As actions do controller só precisam se preocupar sobre o projeto, então elas são bem convencionais. Como antes, a atualização de tarefas será tratada no model Project:


# Arquivo: app/controllers/projects_controller.rb
def edit
  @project = Project.find(params[:id])
end

def update
  params[:project][:existing_task_attributes] ||= {}

  @project = Project.find(params[:id])
  if @project.update_attributes(params[:project])
    flash[:notice] = "Successfully updated project and tasks."
    redirect_to project_path(@project)
  else
    render :action => 'edit'
  end
end

Um detalhe importante: a primera linha da action update seta o parâmetro existing_task_attributes para um hash vazio, se ele já não está setado. Sem esta linha, não teria como deletar a última tarefa de um projeto. Se não existem campos de tarefa no form (porque nós removemos todos eles com JavaScript), então existing_task_attributes() não será setado pelo form, o que significa que o nosso método Project#existing_task_attributes= não será invocado. Setando um hash vazio aqui, se existing_task_attributes() está vazio, garante que o método Project#existing_task_attributes= é chamado ao deletar a última tarefa.

A partial de form não precisa de alterações. No entanto, quando nós submetemos o form com tarefas existentes, o hash params[:project] irá incluir uma key chamada existing_task_attributes. Isto é, quando nós atualizamos o projeto, os parâmetros do POST irão se parecer com isto:


"project" => {
  "name" => "Yard Work" ,
  "existing_task_attributes" => [
    {
      "1" => {"name" => "rake the leaves" },
      "2" => {"name" => "paint the fence" },
    }
  ]
  "new_task_attributes" => [
    { "name" => "clean the gutters" }
  ]
}

Para tratar isto, nós precisamos adicionar um método existing_task_attributes= ao nosso model Project, que irá receber cada tarefa existente e aí vai: ou atualizar a tarefa ou deletá-la, dependendo se os atributos são passados:


# Arquivo: app/models/project.rb
after_update :save_tasks

def existing_task_attributes=(task_attributes)
  tasks.reject(&:new_record?).each do |task|
    attributes = task_attributes[task.id.to_s]
    if attributes
      task.attributes = attributes
    else
      tasks.delete(task)
    end
  end
end

def save_tasks
  tasks.each do |task|
    task.save(false)
  end
end

Note que nós estamos salvando as tarefas em um callback chamado after_update. Isto é importante porque, diferente de antes, as tarefas existentes não serão automaticamente salvas quando o projeto for atualizado. E já que os callbacks são encapsulados em uma transação, se algum problema inesperado acontecer será feito um roll back.

Ao passar false para o método task.save, os dados são salvos sem passar pela validação. Ao invés disso, para garantir que todas as tarefas sejam validadas quando o projeto é validado, nós simplesmente adicionamos esta linha ao model Project:


validates_associated :tasks

Isto vai garantir que tudo é valido antes de salvar. E se a validação falha, então o uso de error_messages_for :project no template de formulário inclui os erros de validação para o projeto e qualquer uma de suas tarefas.

Então agora nós podemos criar e editar projetos e suas tarefas em uma tacada só. E ao usar atributos virtuais, nós mantemos o código do controller felizmente ignorante que nós estamos tratando vários models a partir de um único formulário.

Discussão

Uma vez que você começa a colocar mais de um model em um único formulário, você provavelmente vai querer criar um helper customizado para mensagens de erro, para fazer coisas como ignorar certos erros e detalhar outros. Veja a receita 17 “Customize as Mensagens de Erro”, na página 91 para saber como escrever um método error_messages_for customizado. (Nota do tradutor: capítulo disponível no livro Advanced Rails Recipes)

Campos de data causam alguns problemas porque, por algum motivo, o Rails remove as chaves [] do nome do campo. Isto pode ser arrumado especificando manualmente a opção :index e setá-lo para uma string vazia se a tarefa é nova:


<%= task_form.date_select :completed_at,
:index => (task.new_record? ? '' : nil) %>

Infelizmente, campos do tipo checkbox não vão funcionar com esta receita porque o valor destes campos não é passado pelo browser quando o checkbox é desmarcado. Portanto, você não tem como saber a qual tarefa um checkbox pertence quando estiver criando um novo projeto. Para resolver este problema, você pode usar um menu select para campos booleanos:


<%= task_form.select :completed, [['No' , false], ['Yes' , true]] %>

Copyright (c) 2008 The Pragmatic Programmers, LLC

ASCIIcasts or RailsCasts made text

Tuesday, January 6th, 2009

Imagine you are doing something in Rails, and you need to remember or even learn how to it.

Maybe you, like me, will try to look at the Railscasts videos. But… searching something that Ryan Bates talked about during the video is not so easy to find. Or maybe you can’t watch a video at all, right now.

Here’s a solution. Eifion Bedford is creating text versions of the well-know screencasts at RailsCasts and posting at this new site called ASCIIcasts.

Great find.

Scaling microblogging services such as Twitter

Friday, December 19th, 2008

There’s a joke in the Ruby and Rails world that says ‘Rails doesn’t scale’, which it’s just a joke to really say: what is scallable is the way you create your app, and that does not depend whether is written in Rails, Perl or even Bash.

So it’s important to know what matters in terms of building a scallable web app. As you know:

Scalability: ability to either handle growing amounts of work in a graceful manner, or to be readily enlarged.

And how do you accomplish that in Ruby/Rails/whatever app you’re writing?

Well, one way to gain further knowledge on the subject is by reading this article. The author explains what is envolved when you need to scale a microblogging service such as Twitter. The author created Nouncer (a developer platform for building microblogs and similar services) and ended up learning quite a lot about the inner-workings and challenges of such an application.

Please do read it, it’s a series of 3 articles:

My thoughts? Scalling is not a solved subject, and it depends on the expertise of the developer/architect on finding ways to identify the fine grained causes for bottlenecks and to deal with them in a rather creative way, cycling between endless monitoring and improvements down the road.

Fun, isn’t? :)

Rails Templates

Thursday, December 4th, 2008

Let’s say you want to create a new Rails app. Every time you run “rails my_app” you usually also do some other steps such as:


# You need to remove the index.html for your app to work:
rm public/index.html

# Maybe you also create some basic Models everytime:
./script/generate scaffold person name:string

# Adding a route to the homepage
# route "map.root :controller => :person"

# Migrating the database
rake db:migrate

# The first commit in Git
git init
git add .
git commit -a -m 'Initial commit'

This problem’s gone. Edge Rails now supports a solution using “Templates”. Running a command like this:


rails blog -m ~/template.rb

You’re passing parameters to the ‘rails’ command, telling everything it needs to be done after the creation of the app directory. Things like installing plugins, removing files, putting some default css and image files in /public, the works! So, inside the template.rb file you’d put something like this:


# template.rb
run "rm public/index.html"
generate(:scaffold, "person name:string")
route "map.root :controller => :person"
rake("db:migrate")

git :init
git :add => "."
git :commit => "-a -m 'Initial commit'"

Cool, isn’t? :)

Better yet, you can use an URL to the rails command, so from any machine you’re using you’ll always have the initialization commands at your disposal. How great is that? :)


rails blog -m http://gist.github.com/31208.txt

For more information on Rails Templates check here and here.

New official 15-minute video for Rails 2.2

Thursday, November 27th, 2008

Finally, an update to the famous video on creating a blog with Rails in 15 minutes. The old version was made back in 2005!

New official 15-minute blog video for Rails 2.2 by Ryan Bates.

Como adicionar suporte a feeds

Wednesday, November 5th, 2008

Imaginei que adicionar suporte a feeds em uma aplicação Rails fosse complicado. Mas uma vez “tomei na cabeça” vendo que o Rails realmente é produtivo de se trabalhar :)

1. Método de consulta que retorna todos os posts. Para criar uma URL de feed para o seu blog, antes de tudo você precisa criar um método que faça uma query que liste todos os posts do blog. Seguindo a filosofia “fat model / skinny controller” este método deve ficar dentro do próprio model “Post”. Vamos criar um método chamado “all_posts”.


# app/models/post.rb
class Post < ActiveRecord::Base
  has_many :comments

  def self.all_posts
    find(:all, :order => "created_at DESC")
  end
end

2. Criando uma action para feeds. Agora vamos adicionar uma action chamada “feed” dentro do controller “posts’. Repare que aqui já estamos usando o método “all_posts” criado no passo anterior.


# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def feed
    @posts = Post.all_posts

    respond_to do |format|
      format.atom
    end
  end
end

3. Adicionando uma rota. Do jeito que está, não existe como acessar a URL http//www.myblog.com.br/feed, porque ainda não temos uma rota para esta URL. Precisamos adicionar esta rota no arquivo config/routes.rb. Note a última linha do arquivo.


# config/routes.rb
  map.root :controller => 'posts'
  map.resources :posts, :has_many => :comments
  map.resources :sessions
  map.feed 'feed', :controller => 'posts', :action => 'feed'

4. Adicionando um template para o feed.. Ok, agora o Rails já sabe que existe uma URL /feed em nosso blog. Mas ele não sabe o que renderizar ali, na action “feed”. Ele só sabe que possui um objeto @posts disponível. Vamos dizer ao Rails como ele deve formatar esse retorno. O exemplo abaixo foi retirado da própria documentação do Rails, do Helper AtomFeedHelper.


# app/views/posts/feed.atom.builder
atom_feed(:language => "pt-BR") do |feed|
  feed.title(h "My blog")
  feed.updated((@posts.first.created_at))

  for post in @posts
    feed.entry(post) do |entry|
      entry.title(post.title)
      entry.content(post.body, :type => 'html')

      entry.author do |author|
        author.name(h "João da Esquina")
      end
    end
  end
end

Você pode testar essa URL em seu browser. Mas provavelmente é melhor testar com o comando curl e ver o resultado completo:


curl --get http://www.myblog.com.br/feed

5. Feed no <HEAD> do site. Pronto, já temos um feed funcionando. Agora precisamos colocar isto em nosso HTML, para dizer ao mundo que nosso blog já tem suporte a feeds :) A melhor forma é usar o helper auto_discovery_link_tag do Rails:


# app/views/layouts/application.html.erb
<head>
  <%= auto_discovery_link_tag(:atom, :controller => 'posts', :action => 'feed') %>
</head>

Agora nosso blog informa aos leitores de feeds, que nossa URL oficial é o /feed que criamos até agora. Mas se você como eu, prefere usar o FeedBurner para isso, ao invés disso faça assim:


# app/views/layouts/application.html.erb
<head>
 <%= auto_discovery_link_tag(:atom, 'http://feeds.feedburner.com/LevyOnRails', :title => "My blog's feed") %>
</head>

Ok. Agora se você informar a url de seu blog, por exemplo, http://www.myblog.com.br/ (sem o /feed) no Google Reader ou outro leitor de feeds experto, ele vai usar o feed do FeedBurner, no meu caso a URL http://feeds.feedburner.com/LevyOnRails. Perfeito!

Mas e se alguém usar a url http://www.myblog.com.br/feed, desconsiderando o que está na tag auto_discovery_link_tag acima? Para isso precisamos adicionar um redirect para o feed.

6. Redirect para o feed. Vamos criar um redirect, de forma que somente o FeedBurner consiga ler a nossa URL /feed. O restante do mundo será redirecionada para a URL do http://feeds.feedburner.com/LevyOnRails. Qual a vantagem disso? Você não terá metade de seus leitores usando o FeedBurner e outra metade usando o feed direto de teu site. Assim você consegue medir 100% a leitura/visitação de seu feed, usando as facilidades disponíveis no site do FeedBurner. Vamos precisar alterar o nosso controller:


# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def feed
    redirect_to 'http://feeds.feedburner.com/LevyOnRails', :status=>307 and return unless request.env['HTTP_USER_AGENT'].match(/feedburner|feedvalidator/i)

    @posts = Post.all_posts

    respond_to do |format|
      format.atom
    end
  end
end

Com isso verificamos a variável do servidor HTTP_USER_AGENT, se esta contém a string “feedburner” ou “feedvalidator”. Se tiver, nós acreditamos que trata-se do FeedBurner, e somente este agent pode acessar nossa URL feed real.

E isso é tudo. Simples, não? :)

Processo de criação de um blog em Rails - Parte 1

Saturday, November 1st, 2008

Esse título poderia ser: “por que não dá para fazer um blog em 15 minutos”. Tudo bem, David Hanson consegue, afinal ele é o cara :)

Estou falando do famoso vídeo de uma criação de um blog em 15 minutos, feito pelo próprio criador do framework Ruby on Rails, David H. Hanson. Se você não viu ainda, veja agora! É interessante ver o quanto um vídeo pode fazer para propagar um produto ou idéia, e para empolgar as pessoas. Muitas pessoas que começam a mexer com Rails dizem “eu vi aquele vídeo de 15 minutos, e fiquei impressionado” (myself included!). Desde a criação deste vídeo em 2005, o Rails já evoluiu muito e hoje o próprio DHH diz que já é possível fazer a mesma coisa em 3 minutos. Para um vídeo mais atualizado veja o screencast do Akita, sobre criação de um blog em Rails 2.x (disponível em inglês e português).

Voltando ao assunto, criar um blog em 15 minutos é fácil. Agora para quem quer aprender Rails no processo de criação de um blog, a história é outra. Você precisa de um blog funcional com: autenticação de administrador, um layout mínimo, controle de versão, algum esquema de deployment automatizado, etc.

Pretendo descrever aqui não um processo de um blog, mas sim o processo que fiz para criar o meu blog. Vamos lá:

Layout: aqui é onde muitos programadores (principalmente eu!) empacam. Criar um layout do zero não é fácil, especialmente se você tem bom gosto e especialmente se já viu muitos sites bons por aí. O layout deste blog ficou bem diferente do que eu havia imaginado, mas até que quebra o galho. Levei 2 semanas para criar uma imagem no Photoshop deste layout. Muito tempo, né? Um designer faz isso em 1 hora, se já tiver uma boa direção sobre o que ele precisa criar. Outra coisa que consumiu um certo tempo foi procurar ícones na web. Você geralmente precisa de ícones para realçar o seu layout, e achar um icon set que te agrade, também pode demorar. No meio desse processo, encontrei um blog de um designer chamado Joel Watson que fala muito sobre o processo de criação de um layout de sites, e o que te faz ser um designer melhor. Está em inglês. Vale a pena ler.

Criar o CSS: essa parte é mais tranquila. Em 1 ou 2 horas você cria o CSS básico, e depois vai aperfeiçoando. Se você precisa aprender CSS nos padrões Web, alguns sites que recomendo são: o blog Tableless, o campus online de vídeos da Visie, o blog Pinceladas da Web e o Revolução Etc.

Hospedagem Rails: deployment de Rails não é simplesmente fazer upload dos arquivos e pronto, site funcionando (a menos que você use Mod_Rails e já tenha o Apache configurado). Com Rails você pode fazer o deployment de uma aplicação usando várias combinações de software: Apache + FastCGI, Mongrel, Mod_Rails (Phusion Passenger), Nginx, Thin, Lighttpd. A maioria dos provedores de hospedagem nem sabe como fazer funcionar um site em Rails. Alguns oferecem o Apache + FastCGI, que não funciona muito bem, e só aguenta um uso bem moderado da aplicação. Ao ver algumas opções no mercado, acabei escolhendo o Rails Playground (plano Developer, a US$ 5 / mês, com opções maiores de plano, para quando o site crescer), mas existem outros como Linode, SliceHost, e outros bem mais caros como Engine Yard, Joyent, e por aí vai. Na Rails Playground uso atualmente Apache + FastCGI (eu sei, totalmente básico sendo que temos Passenger, Mongrel, e outros), mas com a opção de mudar para Mongrel quando precisar. E é até interessante começar algo com a versão simples, e ir sentindo a necessidade de escalar a aplicação. E nesse processo todo, você aprende muito sobre deployment de Rails. Você primeiro escala o teu código, fazendo o melhor com o que você tem, e só aí parte pra mudanças no servidor. O investimento de ter uma conta de hospedagem em um provedor que entende de Rails vale muito a pena, altamente recomendado para quem quer aprender Rails.

Controle de versão (Git, é claro!): o Akita fala muito disso no Rails Brasil Podcast. E não é pra menos. É impossível você criar uma aplicação sem ter um controle de versão das alterações. E aqui entra o Git, um software opensource de controle de versão criado pelo Linus Torvalds, sim ele mesmo, o criador do Linux. Em 1 semana esse cara criou um controlador de versão, descontente com as opções existentes no momento (em 2006).

Repositório do código (GitHub, é claro!): depois de criar um código inicial da tua aplicação, ou pelo menos o arquivo README que seja, você precisa colocar isto em um repositório de onde você possa acessar remotamente e trabalhar no código sempre que quiser. Funciona assim: você cria uma conta no GitHub, e envia a tua aplicação para o site. Depois sempre que você quiser trabalhar em cima da aplicação, você “baixa” o código para tua máquina local, trabalha nas alterações, faz teus commits, e depois envia as atualizações para o repositório. Você pode usar o plano free, onde teus projetos são considerados open-source, e assim todos podem abrir e ver teu código. Ou você pode usar um plano pago, a partir de U$ 7/mês, e criar projetos privados, que só você pode ver.

Deployment da aplicação: Capistrano é uma solução em Ruby, que funciona na tua própria máquina. Funciona como um script que faz em sequência, todas as tarefas que você faria para colocar um site em produção:

  • entra por SSH no servidor de produção;
  • gera um tar.gz do conteúdo atual do site;
  • envia o conteúdo novo do site;
  • corrige permissões em arquivos;
  • roda Migrations, no servidor de banco de dados;
  • restarta o servidor Web;

É altamente recomendado, e depois de configurado você só precisa rodar “cap deploy” para subir uma nova versão para produção.

Em breve, teremos a próxima parte da série de posts sobre como foi criar este blog, usando Ruby on Rails. Stay tuned! :)