Deixando meus métodos de pesquisa mais espertos

6 de novembro de 2007  |  Ruby on Rails  | 

1858685882_35f2f01bca.jpg

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.


4 Comentários


  1. Boa dica! Mas como fica o escape do SQL nesta nova forma? Há alguma mudança em relação à forma anterior?

  2. Muito bom! Guardei nos favoritos, já vou refatorar umas coisas…

  3. Rodrigo, o problema dos SQL injection acontece somente quando VC monta a string, por exemplo:

    “type = #{type}”

    Neste caso, pode ficar tranqüilo!

  4. 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

  1. Melhorando as condições em seus métodos de pesquisa « Learning on Rails

Deixe um comentário