Web,ruby, Ajax ou qualquer outra coisa que me venha a cabeça (com prioridade para esta última)

10 dezembro, 2005

RoR 3

Correspondência Automatizada

Active Record efectua automaticamente a correspondência entre tabelas e classes, linhas a objectos (exemplos das classes modelos), e colunas para atributos de objectos. Por exemplo:


class Produto < ActiveRecord::Base
end

é feita corresponder de forma automática à tabela designada produtos, tal como:


CREATE TABLE produtos (
  id int(11) NOT NULL auto_increment,
  name varchar(255),
  PRIMARY KEY (id)
);

que cria também automaticamente um atributo name que pode usar como em:


meu_produto = Produto.find(:first)
STDOUT.print meu_produto.name
meu_produto.name = "Novo Nome do Produto"

Active Record usa regras de formação de plurais em inglês para efectuar a correspondência entre classes e tabelas. O nome da classe modelo fica no singular e com letra maíscula inicial, enquanto o nome da tabela é plural e com letras minúsculas. Exemplos disto incluem:

  • Uma classe modelo de Factura corresponde a uma tabela de facturas.
  • Uma classe modelo Person corresponde à tabela people que é o respectivo plural.
  • Uma classe modelo Country faz-se corresponder a uma tabela countries.
  • Uma class modelo NivelSeguranca corresponde a uma tabela nivel_segurancas.

A convenção singular/plural resulta em código (que em inglês) se lê de forma relativamente normal. Note que a correspondência é inteligente no uso das regras de formação de plurar em inglês. Note-se ainda que os nomes das classes usam maísculas (CamelCase) para separar palavras (o que é uma convenção Ruby), enquanto os nomes das tabelas são na sua totalidade em minúculas e têm traços de sublinhado entre as palavras.

Nos casos em que isto não funciona (tais como quando se faz um interface com bases de dados antigas onde não se tem controlo dos nomes), pode explicitamente dizer ao Active Record que nomes deve usar.

A documentação de ActiveRecord::Base explica com mais detalhe a correspondência automátoca de Active Record.

Associações

Nenhuma tabela fica sozinha. Bem, não é habitual que tal suceda. A maior parte das aplicações de base de dados usam várias tabelas com relações específicas entre essas tabelas. Pode dizer ao Active Record que relações existem e o Active Record irá geral um conjunto de métodos de navegação que tornam fácil ao seu código aceder a dados relacionados. Os modelos seguintes:


class Firma < ActiveRecord::Base
  has_many   :clientes
  has_one    :conta
  belongs_to :grupo
end

permite-lhe escrever código como este:


minha_firma = Firma.find(:last)
STDOUT.print minha_firma.conta.name
STDOUT.print minha_firma.grupo.empregado_contador
for c in minha_firma.clientes
  STDOUT.print "Cliente: " + c.name + "\n"
end

Este código irá trabalhar correctamente quando a base de dados tiver tabelas de clientes e contas, onde cada uma tiver uma coluna name e um tabela grupos que tem uma coluna empregado_contador.

A documentação ActiveRecord::Associations explica com mais detalhe as associações.

Validação

Visto não desejar só guardar uma coisa velha na sua base de dados, irá querer validar os seus dados antes de os guardar. O Active Record contem um conjunto de validadores semelhantes a macros que pode adicionar ao seu modelo.


class Conta < ActiveRecord::Base
  validates_presence_of     :subdominio, :name, :endereco_email, :palavra_de_passe
  validates_uniqueness_of   :subdominio
  validates_acceptance_of   :condicoes_de_servico, :on => :create
  validates_confirmation_of :palavra_de_passe, :endereco_email, :on => :create
end

Se as macros integradas de validação não poderem fazer o que necessita pode sempre escrever os seus métodos de validação próprios.


class Pessoa < ActiveRecord::Base
  protected
    def validate
      errors.add_on_empty %w( nome_proprio, nome_familia )
      errors.add("numero_telefone", "tem formato invalido") unless numero_telefone =~ /[0-9]*/
    end

    def validate_on_create # só é executado da primeira vez que um objecto é guardado
      unless valid_discount?(desconto_socio)
        errors.add("desconto_socio", "expirou")
      end
    end

    def validate_on_update
      errors.add_to_base("Não ocorreram alterações") if unchanged_attributes?
    end
end


pessoa = Pessoa.new("nome_proprio" => "David", "numero_telefone" => "o quê?")
pessoa.save                         # => falso (e não grava)
pessoa.errors.empty?                # => false
pessoa.contador                        # => 2
pessoa.errors.on "nome_familia"        # => "não pode ser vazio"
pessoa.errors.on "numero_telefone"     # => "tem formato inválido"
pessoa.each_full { |msg| puts msg } # => "O apelido não pode ser vazio\n" +
                                            "Número de telefone em formato inválido"
pessoa.attributes = { "nome_familia" => "Afonso", "numero_telefone" => "555-555" }
pessoa.save # => true (e pessoa é agora guardado na base de dados)

Se existir um método validate a RoR irá chamá-lo imediatamente antes de escrever um objecto na base de dados. Se a validação falhar ele não escreve o objecto na base de dados. validate_on_create e validate_on_update são similares, excepto que o primeiro é chamado antes de RoR criar um novo registo na base de dados enquanto o seguinte é chamada quando RoR está praticamente a actualizar um registo existente.

Pode validar um atributo específico só quando uma determinada condição seja verdadeira.


# São possíveis validações condicionais tais como:
  validates_numericality_of :rendimento,   :if => :empregado?
  validates_confirmation_of :palavra_de_passe, :if => :nova_palavra_de_passe?

# Usar blocos
  validates_presence_of :nome_do_utilizador, :if => Proc.new { |utilizador| utilizador.assinalar_entrada > 1 }

A documentação ActiveRecord::Validations explica a validação com mais detalhe.

Continua...

Sem comentários: