Archive for the ‘activerecord’ Category
Nova versão da gem brcpfcnpj
Update: Se alguém ainda estiver tendo problemas com o brcpfcnpj, atualizem o Brazilian-Rails para versão 2.1.1 ou superior que os problemas citados nos comentários abaixo foram solucionados.
Há um tempo atrás descobrimos que a gem brcpfcnpj, parte integrante do projeto brazilian-rails, tinha um pequeno problema para trabalhar em conjunto com as validações do Rails. Por padrão, qualquer atributo usado com usar_como_cpf ou usar_como_cnpj passava a ser automaticamente validado quanto ao seu formato (além da validação do conteúdo do número de documento em questão). Entretanto, não há validação automática para garantir esses atributos não são vazios ou que devem ser sempre únicos.
A solução mais óbvia seria simplesmente escrever código como estes:
class Cliente < ActiveRecord::Base usar_como_cpf :cpf validates_presence_of :cpf validates_uniqueness_of :cpf end
class Empresa < ActiveRecord::Base usar_como_cnpj :cnpj validates_presence_of :cnpj validates_uniqueness_of :cnpj end
O problema disso é que até o Rails 2.1, se você usasse os códigos acima, a coisa não funcionaria direito. Isso porque por baixo dos panos o brcpfcnpj utiliza estruturas do tipo composed_of e esse tipo de construção não trabalhava bem com as macros de validação do Rails. Mais precisamente, se você tentasse usar um validates_uniqueness_of junto com um usar_como_cpf, todo o objeto da classe Cpf seria convertido para uma string (usando to_s, ou seja, não o que queremos) e o resultado disso seria colocado na cláusula where da query SQL feita no banco. Resumindo: Não retornava nada e mesmo que o seu cpf ou cnpj já estivessem gravados no banco, seu objeto continuaria válido.
A partir do Rails 2.2 isso mudou, pois foi alterada a forma com que o composed_of trabalha (e eu me aproveitei deste fato). A partir de agora, caso esteja utilizando o Rails 2.2 ou superior no seu projeto e estiver usando a gem brcpfcnpj, você pode escrever código como o descritos nos exemplos acima e tudo vai funcionar perfeitamente. Caso você ainda esteja no Rails 2.1 ou inferior, continua como antes: A gem irá validar perfeitamente o conteúdo do seu cpf ou cnpj, mas será necessário simular o comportamento das macros escrevendo validações na mão, caso você precise desse tipo de validação. Mais um incentivo para você atualizar o Rails nas suas aplicações.
Para baixar o brazilian-rails com a nova versão do brcpfcnpj, basta fazer
gem install brazilian-rails
cnpj, c
Seu model não pode ter um atributo chamado “type”, seu burro!
Essa me pegou hoje… Como raramente utilizo single table inheritance, esqueci que type é uma palavra reservada no Active Record. Criei um novo model e tasquei um atributo type na migration… o que aconteceu quando fui criar uma factory com o Factory Girl para testar a coisa toda?
client_factory.rb:12:in `type': wrong number of arguments (1 for 0) (ArgumentError)
Ainda bem que uso testes :-)
Tarefa para casa: Escrever 1000x no VI: “Não posso criar um atributo chamado ‘type’ em um model Active Record”
Foi só trocar o nome do atributo para outra coisa qualquer (no meu caso troquei para ‘category’) e pronto.
Usando a opção :through no has_many
Que os métodos para associações entre models do ActiveRecord quebra um galhão todo mundo sabe. O interessante é que quando não conhecemos e/ou estamos habituados a utilizar os recursos do ActiveRecord, existe uma forte tendência a não utilizar estes métodos para associação ou ainda escrever métodos de pesquisa com sentenças SQL puras, usando o famigerado find_by_sql. O fato é que sempre que possível deve-se usar os recursos disponíveis pelo AR, pois isso gera um código mais limpo, legível e, para os puristas de plantão, mais OO.
O AR tem muitos recursos para facilitar a associação entre os models e tornar automáticas (ou quase) buscas que de outra forma exigiriam a criação de sentença SQL complexas cheias de joins. Um destes recursos é a opção has_many, através da qual podemos dizer coisas como “um carro tem muitas peças”.
class Peca < ActiveRecord::Base belongs_to :carro end class Carro < ActiveRecord::Base has_many :pecas end
E podemos usar isso assim
@carro = Carro.find(1) @pecas = @carro.pecas # <= retorna uma lista de objetos da classe Peca
Essa busca é feita através das chaves primárias/estrangeiras presentes nas tabelas. Na verdade voc6e não precisa ter essas contraints realmente criadas no banco, desde que obedeça certos critérios de nomenclatura para as colunas das suas tabelas. No exemplo acima, o Rails vai assumir que uma coluna chamada carro_id na tabela pecas indica a coluna id da tabela carros e assim relaciona os dois models.
Um exemplo mais complexo seria o caso onde temos um esquema do tipo:
- Uma empresa tem vários clientes
- Cada cliente possui várias faturas
Neste cenário, podemos querer pesquisar todas as faturas de uma determinada empresa. O problema é que não existe na tabela faturas uma coluna chamada empresa_id. Como o Rails vai então relacionar as coisas?
A tabela clientes possui essa coluna empresa_id!
Podemos então utilizar a opção :through da associação has_many, e fazer com que o ActiveRecord utilize um join para associar as tabelas “empresas” e “faturas” através da tabela “clientes”. Assim:
class Empresa < ActiveRecord::Base has_many :clientes has_many :faturas, :through => :clientes end class Cliente < ActiveRecord::Base belongs_to :empresa has_many :faturas end class Fatura < ActiveRecord::Base belongs_to :cliente end
E podemos fazer coisas como
@empresa = Empresa.find(1) @faturas = @empresa.faturas
O Rails vai pesquisar o banco usando um SQL mais ou menos assim (que você não precisou escrever!):
SELECT "faturas".* FROM "faturas" INNER JOIN clientes ON faturas.cliente_id = clientes.id WHERE (("clientes".empresa_id = 1))


