
Imagine o seguinte método:
def count_users(type) User.count(:all, :conditions => ["type = ?", type]) end
É um método simples, que irá me retornar a quantidade de usuários de um determinado tipo. Agora, vamos testar nosso método (preste atenção aos comandos SQL gerados):
>> count_users(1) => 2 SELECT count(*) AS count_all FROM users WHERE (type = 1) >> count_users(2) => 5 SELECT count(*) AS count_all FROM users WHERE (type = 2)
Ok, até aqui tudo funciona perfeitamente, mas e se eu desejasse contar todos os usuários que tivessem a coluna type com o valor NULL?
>> count_users(nil) => 0 SELECT count(*) AS count_all FROM users WHERE (type = NULL)
Opa, eu tenho um registro no meu banco com o valor NULL, mas o meu método retornou zero. O que saiu errado? Note a query gerado pelo comando, type = NULL está errado, deveríamos usar type IS NULL.
Preciso alterar meu método:
def count_users(type)
User.count(:all, :conditions => {:type => type})
end
Note que alterei a forma como o parâmetro :conditions estava sendo usado. Neste caso especifico, meu método ficou muito mais robusto. Veja alguns exemplos:
>> count_users(1) => 2 SELECT count(*) AS count_all FROM users WHERE (users."type" = 1) >> count_users(2) => 5 SELECT count(*) AS count_all FROM users WHERE (users."type" = 2) >> count_users(nil) => 1 SELECT count(*) AS count_all FROM users WHERE (users."type" IS NULL) >> count_users([1,3]) => 3 SELECT count(*) AS count_all FROM users WHERE (users."type" IN (1,3)) >> count_users(1..3) => 8 SELECT count(*) AS count_all FROM users WHERE (users."type" BETWEEN 1 AND 3)
Note que agora, mesmo passando nil ou um array para o método, ele criará a query de pesquisa da forma correta de acordo com o tipo do objeto usado.

5 Comentários em "Deixando meus métodos de pesquisa mais espertos"
Boa dica! Mas como fica o escape do SQL nesta nova forma? Há alguma mudança em relação à forma anterior?
Muito bom! Guardei nos favoritos, já vou refatorar umas coisas…
Rodrigo, o problema dos SQL injection acontece somente quando VC monta a string, por exemplo:
“type = #{type}”
Neste caso, pode ficar tranqüilo!
Passar um hash ao invéz de uma array para :conditions é bem melhor e mais seguro.
Mas o hash trabalha com “AND”. Você saberia como fazer para o conditions trabalhar com “OR” para juntar as chaves?
Trackbacks/Pingbacks
[...] uma dica muito legal sobre o parâmetro conditions dos métodos de pesquisa do Rails. Vale a pena conferir. Filed under: Dicas, Rails [...]
Deixe o seu comentário!