Squirrel, uma boa opção para querys complexas


English Version (Google Translate)

Na semana passada me deparei com um formulário de buscas que deveria efetuar uma query de acordo com uns 20 campos (1 campo para cada atributo do Model) e ainda precisava aceitar intervalos em alguns campos de data e valor.

Para fazer este tipo de busca usando os finders padrão do Rails eu teria que passar um hash enorme para o argumento conditions… definitivamente uma péssima solução. A outra solução seria pensar em usar Sphinx mas o problema é que ele não é tão bom para conteúdo que não seja texto (como os intervalos numéricos que citei acima) e ainda eu precisaria migrar o sistema do meu cliente de sharedhost para vps única e exclusivamente para usar o daemon do Sphinx.

Então a solução que encontrei foi o Squirrel, um plugin desenvolvido pela ThoughtBot que consegue estender os finders do ActiveRecord para algo mais rubista.

Como por exemplo (exemplo retirado do site do Squirrel):

1
2
3
4
5
6

User.find(:all) do
  first_name == "Jon"
  email =~ "%@thoughtbot.com"
  created_at >= 4.years.ago 
end

Desta forma o nosso código fica muito mais legivel quando é necessário criar condições mais complexa. Veja abaixo como ficou um trecho da query para a seção de buscas que citei no começo do post:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

def self.search(query, options = {})
  find :all do
    paginate options
    all do
      user.name.contains?    query[:user] if query[:user].present?
      address.contains?    query[:address] if query[:address].present?
      city.contains?           query[:city]  if query[:city].present?
      description.contains?    query[:description]  if query[:description].present?
      observation.contains?    query[:observation]  if query[:observation].present?

      if query[:min_area].present? && query[:max_area].present?
            area <=> (query[:min_area].to_i..query[:max_area].to_i) 
      end  
      #... muito mais codigo ...

      category == query[:category] if query[:category].present?
      garage >= (query[:garage].to_i) if query[:garage].present?
    end
    order_by address
  end
end

No método acima (que está dentro do Model) também passamos options para o método paginate, isto funciona pois o Squirrel é compatível com WillPaginate e você não precisa fazer nada além de chamar este método.

Para um exemplo mais completo e mais detalhes acesse: Squirrel


Comentário