Edge Rails: Tratando a opção :limit como bytes (atualizado)

Publicado por Carlos Brando em 22 de Julho de 2008

À partir da próxima versão do Rails quando usarmos a opção :limit para colunas com números inteiros, em nossas migrations, estaremos nos referindo ao número de bytes, no MySQL e no PostgreSQL (no sqlite sempre foi assim).

O tipo da coluna no banco de dados dependerá da quantidade de bytes espeficida. Veja o trecho de código que identifica o tipo da coluna para o MySQL:

when 1; 'tinyint'
when 2; 'smallint'
when 3; 'mediumint'
when nil, 4, 11; 'int(11)' # compatibility with MySQL default
when 5..8; 'bigint'
else raise(ActiveRecordError, "No integer type has byte size #{limit}")

E para o PostgreSQL:

when 1..2; 'smallint'
when 3..4, nil; 'integer'
when 5..8; 'bigint'

Edge Rails: Algumas correções de bugs

Publicado por Carlos Brando em 21 de Julho de 2008

Algumas correções de bugs que sairão na próxima versão do Ruby on Rails:

ActiveRecord

  • Correção de uma colisão entre named_scope e :joins.
    Quando se usava with_scope junto com :joins todos os atributos da tabelas secundárias eram adicionados ao modelo da tabela principal.
  • Partial updates não atualizavam o lock_version se nada foi alterado.
    Quando usávamos optimistic locking com partial updates, tinhamos queries extras quando na verdade elas não eram necessárias.

Edge Rails: Uma nova forma de especificar conditions usando Hash 1

Publicado por Carlos Brando em 15 de Julho de 2008

Ao realizar buscas no banco de dados, por vezes temos de fazer uso da opção :joins afim de melhorar a performance de nosso aplicativo, em outros casos precisamos simplesmente recuperar algum tipo de informação que depende do resultado de duas tabelas.

Por exemplo, se desejássemos recuperar todos os usuários do sistema que compraram itens da cor vermelha, faríamos algo assim:

User.all :joins => :items, :conditions => ["items.color = ?", 'red']

Este tipo de sintaxe parece incomodar já que você precisa incluir o nome da tabela (no caso items) dentro de uma string. O código parece estranho.

No Edge Rails já se encontra uma novidade nesta questão, nos permitindo fazer a mesma coisa de uma forma um pouco diferente, usando uma chave dentro do hash para identificar a tabela:

User.all :joins => :items, :conditions => {
  :age => 10,
  :items => { :color => 'red' }
}

# um outro exemplo que talvez deixe o código mais claro
User.all :joins => :items, :conditions => {
  :users => { :age => 10 },
  :items => { :color => 'red' }
}

Na minha opinião desta forma o código fica muito mais claro, principalmente se temos de condicionar muitos campos de várias tabelas diferentes.

Só tenha em mente que a chave usada é o nome da tabela (você percebe pelo nome pluralizado) ou um alias caso você o tenha especificado na query.

Edge Rails: Definindo como o método validates_length_of deve funcionar 1

Publicado por Carlos Brando em 09 de Julho de 2008

O método validates_length_of faz parte dos muitos métodos de validação contidos no ActiveRecord. Este método em particular serve para garantir que o valor gravado em uma determinada coluna no banco de dados terá um tamanho máximo, mínimo, exato, ou até mesmo se está em um intervalo de valores.

Mas o termo “tamanho” é relativo. Hoje quando dizemos “tamanho” estamos nos referindo a quantidade de caracteres no texto.

Mas imagine um caso onde eu tenha um campo em um formulário onde a limitação não seja definida pela quantidade de caracteres e sim pela quantidade de palavras, algo como “escreva um texto com no mínimo 100 palavras”. Imagine uma página onde o usuário tenha de redigir uma redação, por exemplo.

Hoje, para validar isto não teríamos outra escolha senão criarmos um novo método que faça esta validação. Mas na próxima versão do Rails poderemos personalizar o método validates_length_of para funcionar da forma como desejamos usando a opção :tokenizer.

Veja um exemplo que resolveria o problema citado acima:

validates_length_of :essay,
                    :minimum => 100,
                    :too_short => "Sua redação deve ter no mínimo %d palavras."),
                    :tokenizer => lambda {|str| str.scan(/\w+/) }

Este é apenas um exemplo do que podemos fazer com esta nova opção. Além disso podemos usa-lá para contar apenas a quantidade de dígitos, menções de uma única palavra, etc..

E então, como você fará uso dessa opção?

Edge Rails: Correção nas tarefas db:migrate:down e :up 8

Publicado por Carlos Brando em 07 de Julho de 2008

Quando se usa o comando rake db:migrate:down VERSION=alguma_versão, os registros na tabela schema_migrations não estão sendo atualizados.

Isto significa que após usar o comando rake db:migrate:down ou up se você rodar o comando rake db:migrate algumas migrations podem não ser executadas. Vamos simular isto para ficar fácil de entender o problema:

$ ./script/generate migration test_migration
      create  db/migrate
      create  db/migrate/20080608082216_test_migration.rb

$ rake db:migrate
(in /Users/erik/projects/railstest)
== 20080608082216 TestMigration: migrating ====================================
-- create_table("foo")
   -> 0.0137s
== 20080608082216 TestMigration: migrated (0.0140s) ===========================

$ rake db:migrate:down VERSION=20080608082216
(in /Users/erik/projects/railstest)
== 20080608082216 TestMigration: reverting ====================================
-- drop_table("foo")
   -> 0.0139s
== 20080608082216 TestMigration: reverted (0.0144s) ===========================

$ rake db:migrate
(in /Users/erik/projects/railstest)

$

Este problema foi corrigido ao se certificar de atualizar a tabela schema_migrations após a execução destas tarefas. Estará disponível na próxima versão do Rails.

Uma outra alteração da qual não posso comentar muito já que não sou muito experiente em PostgreSQL é que o Active Record agora aceita fazer isto:

:conditions => [':foo::integer', { :foo => 1 }]

Peço aos mais experientes que comentem sobre isto.