Tag: rubyonrails

Rails =~ /Merb/

23 de dezembro de 2008 às 23:29 | Carlos Júnior | , ,

“Anh?” É, eu também fiz essa cara que você está fazendo quando li o artigo do blog oficial do rails. Mas é isso mesmo:

Rails 3.0 é a próxima major version, e englobará nada menos que o (seu antes arqui-rival) Merb. Não só isso, Merb+Rails serão juntos o Rails 3.0. E os preparativos já começaram! wycats já é parte do Rails Core Team, o plano de ação já foi feito e o Merb já até tem uma página especial no site oficial do rails.

Para quem não conhece (Sério? Você precisa atualizar seus feeds…), Merb é um outro grande framework Ruby, que tem como princípios desde o seu nascimento ser rápido, 100% modularizado e Thread-safe. A forma de se desenvolver no Merb é bastante parecida com Rails (como era de se imaginar), porém com algumas particularidades. Leia mais no site oficial do Merb.

O que isso trará de bom para o Rails

Em primeiro lugar a fusão trará para o Rails a política de liberdade do Merb. No Merb, você não é obrigado a usar DataMapper (o ORM padrão), ou obrigado a usar ERb (para renderizar a view) e etc, eles são apenas padrões sugeridos, o que não acontece no Rails, onde você precisa fazer uma forcinha para mudar estes padrões. No Rails 3.0 esta abordagem de liberdade também fará parte de nossas vidas, sendo simplificado o uso de DataMapper e Sequel.

Desta forma, teremos um “rails-core”, assim como o merb-core, que será o rails sem nenhum módulo. De qualquer forma, ainda haverá um pacote “rails” que nos trará toda a pilha de módulos do rails.

Otimizações na performance do Rails será um outro benefício que este merge nos trará. O Merb tem muitas partes do Rails reescritas com melhorias de performance que também serão parte do Rails 3.0.

No Merb, os plugins tem uma API fixa, o que significa que os plugins escritos não quebram a cada nova versão do framework. Esta linha de pensamento será trazida para o Rails 3, aumentando ainda mais nossa gama de plugins e  a facilidade de manter o desenvolvimento de um.

A base de usuários… ahh, a base de usuários… :D O Rails contará agora com praticamente todos os desenvolvedores Ruby disponíveis como sua base até por que, coincidência ou não, desde o dia 17/12/08 já poderemos usar o Sinatra de forma fácil dentro de uma aplicação Rails (ainda edge, futura 2.3).

Nas palavras do próprio Yehuda Katz, de forma geral, olharão para o Merb e trarão para o Rails o que ele tiver de melhor e ainda faltar ao Rails.

A migração

A migração promete não ser penosa. Segundo o post de anúncio do merge, migrar um aplicativo Rails 2 para Rails 3 será relativamente ‘tranquilo’, assim como migrar aplicações Merb para Rails 3.

Quem mantém aplicações Merb não precisa se preocupar, já a versão atual do Merb continuará sendo mantida com bugfixes e pequenas alterações já previstas. Daí pra frente, tudo será Rails 3.0.

Novo no Rails Edge: Suporte simples a “Conditional-Get” (ETags)

14 de agosto de 2008 às 02:24 | Carlos Júnior | ,

O Carlos Brando vem fazendo um excelente trabalho em trazer para nós as novidades do Rails Edge (no caso, o 2.2). Mas ao me deparar com esta atualização não pude me conter em blogar sobre. Na verdade, apenas traduzir o artigo do Ryan.

———–

Conditional-gets são uma facilidade da especificação do HTTP que fornece um método de os servidores we comunicarem aos brosers que a resposta para a requisição GET não mudou desde a última requisição e que o cache do browser pode ser usado com segurança.

Eles funcionam usando os cabeçalhos HTTP_IF_NONE_MATCH e HTTP_IF_MODIFIED_SINCE para passar para frente e para trás um identificador único do conteúdo e o timestamp de quando o conteúdo foi modificado pela última vez. Se o browser fizer a requisição onde o identificador do conteúdo (etag) ou a data da última modificação bater com a versão do servidor então o servidor precisa apenas enviar de volta uma resposta vazia com um status de “não modificado” (304).

É do servidor (nós) a responsabilidade de olhar a data da última modificação e o cabeçalho if-none-match e determinar quando ou não enviar a resposta completa (com a renderização da página, por exemplo). Com este novo suporte a conditional-get no rails, isto se torna uma tarefa muito fácil:

class ArticlesController < ApplicationController
    def show
        @article = Article.find(params[:id])
 
        # Define o cabeçalho da resposta para refletir exatamente
        # o estado do objeto requisitado
        response.last_modified = @article.published_at.utc
        response.etag = @article
 
        # Se o estado da requisição é o mesmo do estado no servidor
        # então sabemos que não precisamos enviar todo o resultado
        if request.fresh?(response)
          head :not_modified
        else
          respond_to do |wants|
            # normal response processing
          end
        end
    end
end

O valor do etag é calculado para você com o metodo setter etag=. Tudo que você tem que fazer é prover um único objeto ou array de objetos que definem de forma única a identificação desta requisição. Neste exemplo o artigo por si mesmo contém toda a informação que identifica o estado desta requisição. De qualquer forma, você pode precisar de usar mais de uma chave em seu aplicativo. Como para uma requisição específica para cada usuário:

response.etag = [@article, current_user]

O método request.fresh?(response) é quem dirá a você se a requisição casa com o valor de last-modified-since ou if-none-match da resposta que está sendo enviada. Se sim, você pode evitar de responder todo o conteúdo e economizar alguma (ou muita!) banda.

Também é possível você evitar de acessar o banco de dados se seu aplicativo trata com páginas completamente estáticas armazenadas no banco de dados (isso é raro):

class ArticlesController < ApplicationController
    def show
        # Se o artigo não muda, o etag pode se basear apenas em
        # ítems que temos na requisição
        response.etag = [:article, params[:id]]
 
        # Se o estado da requisição é o mesmo do servidor
        # podemos evitar também de acessar o banco de dados
        if request.fresh?(response)
          head :not_modified
        else
          @article = Article.find(params[:id])
          respond_to do |wants|
            ...
          end
        end
    end
end

Então, seja um bom cidadão e faça suas requisições compatíveis com conditional-get. Isto é a coisa certa a ser feita – e melhoram também a performance de seus programas.

—-

Vale notar, que você pode também usar estes cabeçalhos para acessar webservices (principalmente os feitos em Rails agora :D ) fazendo requisição de XML, se você, por exemplo, estiver guardando os dados que você acessou e guardar a data em que isto foi feito, assim você economisa ainda mais banda!

Rails DataBrowser no rubyforge!

7 de junho de 2008 às 17:39 | Carlos Júnior | ,

Agora você também pode instalar o Rails DataBrowser via RubyGems!

update 25/06/08: o site do Rails DataBrowser mudou! Abandonamos o uso do Trac, e agora estamos com o Redmine. Então acesse redmine.milk-it.net/projects

Acabei de publicar a gem no RubyForge, e esta será atualizada constantemente assim como o plugin!

Bom, para installar:

gem install databrowser

Para usar:

require 'data_browser'
ActionController::Routing::Routes.draw do |map|
  # your routes
  map.databrowser
end

Ou, se você está usando Rails >= 2.1, ao invés de fazer o require no routes.rb, adicione esta linha em seu environment.rb

  config.gem "databrowser", :lib => "data_browser"

Espero que gostem!

Comentários desativados

Suporte a TimeZone no Rails 2.1: uma visão geral

13 de abril de 2008 às 16:06 | Carlos Júnior | , ,

Esta é uma tradução do artigo escrito por Geoff Buesing.

Este será o primeiro de muitos posts que farei sobre os novos recursos de time zone (fuso horário) na próxima versão (2.1) do Rails. Neste post, eu darei uma visão geral destes novos recuros, na criação de um novo aplicativo.

Começarei com um aplicativo Rails 2.1 criado através do comando “rails”. No 2.1, suporte a fuso horário estará ligado por padrão no environment.rb, através da opção config.time_zone:

# config/environment.rb
config.time_zone = 'UTC'

– Este estará definido para UTC como padrão, mas você irá normalmente modificar isto para um fuso horário apropriado para sua localidade. As novas tarefas do rake time:zones:all, time:zones:us, e time:zones:local foram adicionadas para ajudá-lo a encontrar os nomes adequados de fuso horário. time:zones:local farão uma tentativa educada baseada no sistema local de horário, então este é um bom lugar para se começar:

$ rake time:zones:local
* UTC -06:00 *
Central America
Central Time (US &amp; Canada)
Guadalajara
Mexico City
Monterrey
Saskatchewan

Carlos: este é o exemplo usado no artigo original, não vou modificar pois os exemplos se baseam nestes resultados…. no meu sistema acontece isso:

$ rake time:zones:local
* UTC -02:00 *
Mid-Atlantic

Para este exemplo, eu usarei config.time_zone para US Central Time:

# config/environment.rb
config.time_zone = 'Central Time (US &amp; Canada)'

A seguir, criarei um simples scaffold para um modelo Task, com um atributo datetime alert_at:

$ script/generate scaffold Task name:string alert_at:datetime
$ rake db:migrate
$ script/server

Irei ao formulário para nova tarefa, e criarei uma:

new_task1.png

A action show exibe a data e hora que eu digitei, seguido pela correção (deslocamento) UTC:

show_task1.png

… para este exemplo, o prefixo UTC é -0500, que é a correção para US Central Time durante o “horário de verão”:

Para mostrar como este horário é guardado no banco de dados, eu vou ao script/console, e usar o método #alert_at_before_type_cast:

>> t = Task.find_by_name('foo')
=>#< Task … >
>> t.alert_at
=> Sun, 06 Apr 2008 10:30:00 CDT -05:00
>> t.alert_at_before_type_cast
=> "2008-04-06 15:30:00"

O banco de dados está guardando a representação UTC de nosso horário: 15:30 UTC é simultâneamente 10:30 CDT (Central Daylight Time – daylight é o horário de verão). A diferença entre os dois horários é a correção UTC (-5 horas, neste caso).

Depois, eu vou editar a tarefa e alterar o mês para Janeiro (fora do horário de verão, lá):

edit_task.png

Note que a correção UTC agora é -0600 – por que o alert_at não está mais no horário de verão.

show_task_updated.png

script/console confirmará que o banco de dados recebeu a representação correta UTC:

>> t = Task.find_by_name('foo')
=> < Task … >
>> t.alert_at
=> Sun, 06 Jan 2008 10:30:00 CST -06:00
>> t.alert_at_before_type_cast
=> "2008-01-06 16:30:00"

A hora do banco de dados é agora 16:30 ao invés de 15:30, por que a correção UTC é -6 horas agora.

Fusos por usuário

O que eu defini anteriormente funcionará bem para um aplicativo onde todos os usuários estão no mesmo fuso. Se o aplicativo eventualmente necessitar suportar usuários em fusos diferentes, é bastante fácil de se fazer isso:

Primeiramente, eu criarei um scaffold de usuário, com um atributo string para guardar o fuso do usuário:

$ script/generate scaffold User name:string time_zone:string
$ rake db:migrate

Mudarei formulário do usuário para usar o combo de fusos ao invés de um campo de texto:

# views/users/new.html.erb
<%= f.time_zone_select :time_zone, TimeZone.us_zones %>

O novo formulário de usuário ficará assim — eu o usarei para criar alguns usuários com fusos diferentes:

new_user.png

Para efeitos de demonstração, eu adicionarei um before_filter simples chamado “login_from_querystring” ao ApplicationController:

# controllers/application.rb
before_filter :login_from_querystring
def login_from_querystring
  @current_user = User.find_by_name(params[:user])
end

Então adicionarei um outro before_filter “set_time_zone”, que definirá o Time.zone para o fuso do usuário atual:

# controllers/application.rb
before_filter :set_time_zone
def set_time_zone
  Time.zone = @current_user.time_zone if @current_user
end

Adicionarei um cabeçalho ao layout para mostrar quem está logado, seu fuso horário e o hora atual em seu fuso horário:

# views/layouts/tasks.html.erb
Current user: <%= @current_user.name if @current_user %>
Current time zone: <%= Time.zone.name %>
Current time: <%= Time.zone.now.inspect %>
<hr />

Finalmente, modificarei a view da index das tarefas para usar a representação #inspect do alert_at, para nos revelar alguns detalhes adicionais:

# views/tasks/index.html.erb
<%=h task.alert_at.inspect %>

Agora, se eu logar com um dos usuários que eu criei, eu verei a tarefa que criei anteriormente, com o alert_at ajustado para o fuso do usuário atual:

index_usuario1.png

…note que o horário exibido para a tarefa é 11:30 EST – que é o mesmo que 10:30 CST.

Para o usuário em US Mountain Time, a tarefa será mostrada como 9:30 MST:

index_usuario2.png

Sem um usuário logado, o fuso usado é o definido em config.time_zone:

index_usuario21.png

Métodos para criar horários no Time.zone atual

Anteriormente, nós estávamos nos apoiando no ActiveRecord para automaticamente converter atributos do model para o horário local do usuário. Para casos onde você precisa criar novas instâncias de Time no fuso local do usuário, os métodos Time.zone.local(), Time.zone.parse() e Time.zone.now() estão disponíveis, assim como Time.zone.now():

>> Time.zone = 'Hawaii'
=> "Hawaii"
> Time.zone.now
=> Wed, 09 Apr 2008 15:48:18 HST -10:00
>> Time.zone.local(2008, 4, 9, 15, 48, 18)
=> Wed, 09 Apr 2008 15:48:18 HST -10:00
>> Time.zone.parse('2008-04-09 15:48:18')
=> Wed, 09 Apr 2008 15:48:18 HST -10:00
>> Time.zone.at(1207792098)
=> Wed, 09 Apr 2008 15:48:18 HST -10:00

Time e DateTime #in_time_zone converterá qualquer instância para o fuso em Time.zone:

>> Time.zone = 'Alaska'
=> "Alaska"
>> t = Time.utc(2000)
=> Sat Jan 01 00:00:00 UTC 2000
>> t.in_time_zone
=> Fri, 31 Dec 1999 15:00:00 AKST -09:00

… ou, para qualquer fuso ou identificador de fuso (ex.: nome, inteiro ou Duration):

>> t.in_time_zone('Hawaii')
=> Fri, 31 Dec 1999 14:00:00 HST -10:00
>> t.in_time_zone(-6.hours)
=> Fri, 31 Dec 1999 18:00:00 CST -06:00

Dica: Atualizando seu aplicativo

  1. o novo recurso de fuso horário assume que seu banco de dados está guardando horários em UTC, então se você está atualmente guardando horários em um fuso diferente de UTC, você precisará migrar os dados existentes para UTC.
  2. se você instalou o plugin tzinfo_timezone, você precisará removê-lo, dado que este sobrescreve a classe TimeZone no ActiveSupport.
  3. a gem TZInfo não é mais necessárioa, dado que esta está agora dentro do ActiveSupport. De toda forma, se você tem uma versão recente desta gem instalada, Rails favorecerá a gem sobre a versão incluída no ActiveSupport.
  4. A versão do TZInfo incluída no ActiveSupport é uma versão compacta da gem, então se você está interagindo com a API do TZInfo diretamente, você precisará da gem instalada.
  5. Se você não deseja usar o novo recurso de fuso horário – este novo recurso não deve interferir em seu código existente, desde que você não declare o config.time_zone em seu environment.rb.

No próximo capítulo…

Nos próximos posts, tentarei cobrir mais coisas “escondidas”, mas esperamos que este post ajude vocês

Se você acha fuso horário, correções UTC, e horário de verão confuso, você talvez queira ver estas validações de fuso horário, que talvez te deixem ainda mais confuso…

Rails DataBrowser lançado!

19 de fevereiro de 2008 às 12:12 | Carlos Júnior | , ,

É com muita satisfação que anuncio que o Rails DataBrowser encontra-se estável e em plena condição de uso :D

update 25/06/08: o site do Rails DataBrowser mudou! Abandonamos o uso do Trac, e agora estamos com o Redmine. Então acesse redmine.milk-it.net/projects

De onde veio?

A vontade de criar o plugin Rails DataBrowser veio de quando conheci o Databrowser do django. Pensei que Rails poderia ter uma ferramenta do tipo e comecei a escrever algo. No primeiro dia ele já estava usável, mas eu não publicaria aquilo (mesmo!). Então, depois de muitas melhorias (inclusive visuais) hoje fiz o commit que marca sua data de lançamento para o público.

O que é?

O DataBrowser lhe permite editar, criar, navegar, visualizar e excluír registros do seu banco de dados através dos Models de sua aplicação. Bom, veja mais detalhes em http://trac.milk-it.net/open/wiki/DataBrowser.

Abraços!