Rails: Autocompletes à moda RESTful
Muita gente tem reclamado que o padrão RESTful do Rails é ruim, que limita, dificulta, etc. Eu não concordo, acho que limitações nos forçam a pensar em soluções mais simples. Realmente, manter-se RESTful não é tão simples quanto sair criando um monte de actions para qualquer coisa, principalmente nos casos de uso de ajax. Uma das reclamações que eu ouvi foi sobre dificuldade em usar autocompletes, por isso nesse artigo vamos ver como resolver esse “problema” e fazer um auto complete RESTful de forma simples e elegante.
Vamos lá, criando o projeto para teste e um resource Pessoa
rails restful_autocomplete cd restful_autocomplete script/generate scaffold pessoa nome:string rake db:migrate
Instalando o plugin auto_complete:
script/plugin install git://github.com/rails/auto_complete.git
É necessário ter o git instalado, caso vc não tenha, ou não esteja com vontade de instalar, baixe o plugin aqui e descompacte em vendor/plugins.
Esse plugin possui uma macro para gerar a action de resposta do auto complete, mas como estamos usando um controller RESTful, não vamos usá-lo dessa maneira. Em vez disso, vamos criar uma mini-API para lidar com o problema. A idéia central é que TODAS as requisições que necessitem recuperar uma coleção de pessoas usem como ÚNICO ponto de acesso a action index.
O plugin espera os registros formatados dentro de uma lista não ordenada, por exemplo:
<ul>
<li>Item 1</li>
<li>Item 2</li>
...
<li>Item N</li>
</ul>
Com isso em mente, vamos criar um novo mime-type para que nosso controller se encarregue de identificar a requisição do auto complete e devolver o formato correto. Adicione a seguinte linha ao arquivo config/initializers/mime_types.rb:
Mime::Type.register_alias "text/html", :autocomplete
Estamos registrando o tipo customizado “autocomplete” como HTML. Lembre-se de reiniciar o servidor depois de alterar o arquivo.
Agora criaremos um controller qualquer que fará a requisição pelo auto complete:
script/generate controller testes new
Na view testes/new.html.erb, coloque o seguinte:
<%=
text_field_with_auto_complete :bla, :ble, { :size => 25 }, {
:url => formatted_pessoas_path(:autocomplete),
:method => :get,
:param_name => 'nome'
}
%>
Passamos algumas opções ao helper text_field_with_auto_complete fornecido pelo plugin:
- Na linha 3 indicamos a url (ou melhor, o RECURSO) à qual a requisição será ser feita e o mime-type que desejamos (o “autocomplete” que nós criamos). A url gerada será /pessoas.autocomplete
- Na linha 4 estamos dizendo que queremos que a requisição seja feita pelo método GET (LEMBRE-SE: A action index só é acessivel por GET em um controller RESTful)
- Finalmente na linha 5 especificamos com qual nome o conteúdo do text_field será enviado. O valor do parâmetro depois poderá ser acessado com params[:nome].
A action index do controller pessoas (nossa “API”), responsável pelo trabalho sujo, ficará assim:
def index
conditions = ["nome LIKE ?", "%#{params[:nome]}%"] if params[:nome]
@pessoas = Pessoa.all :conditions => conditions
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @pessoas }
format.autocomplete { render :inline => "<%= auto_complete_result @pessoas, :nome %>" }
end
end
A idéia básica de uma API, é que ela receba parâmetros, processe-os, e devolva um resultado. Nossa API é extremamente simples, se receber um parâmetro “nome”, faz a pesquisa pelos nomes que forem similares, senão retorna todos os registros. Podemos incrementar nossa API e adicionar várias outras coisas, como mais opções para pesquisa (pesquisa por idade, por CPF…), limite de registros a serem retornados, paginação, e o que mais for preciso. Essa é a maior vantagem do padrão RESTful, em vez de uma action, você ganha uma API
.
A linha 7 é que faz a mágica de responder ao auto complete. Ela devolve os resultados da pesquisa no formato que o auto complete espera, na forma de lista não ordenada, usando o helper auto_complete_result.
Inicie o servidor, e acesse a url http://localhost:3000/testes/new e teste o auto complete.
Pronto, temos um auto complete RESTful! =)
Lembre-se, o modelo RESTful veio para facilitar nossa vida, não para complicar. RESTful restringe visando simplificar o design de nossas aplicações e nos forçar a construir APIs que nós mesmos consumimos (e obviamente, também ser consumidas por terceiros). Limitações são impostas apenas por nós mesmos, por isso, pare de se limitar
.
NOTA 1: Não esqueça de incluir os javascripts necessários no seu layout, senão não vai funcionar:
<%= javascript_include_tag :defaults %>
NOTA 2: Os helpers de rotas formatados serão removidos nas próximas versões do Rails. Em vez de:
formatted_pessoas_path(:autocomplete)
Ficará:
pessoas_path(:format => :autocomplete)
Então atenção à versão do Rails que vc está usando. Mais detalhes aqui.
Me recomende
Muito bem explicado.. já tive dificuldades no passado para usar autocomplete, acabei criando uma div para fornecer os resultados..
Favoritado!
fabianosoriani
April 2, 2009 at 6:05 pm