Uma funcionalidade básica super comum em aplicações web é a pesquisa. Essa é uma boa funcionalidade para discutirmos aqui, pois ela é razoavelmente simples e podemos falar sobre criação de formulários, queries e rotas, três assuntos fundamentais para desenvolvimento de aplicações web. Então aqui usaremos como exemplo uma aplicação hipotética em que são catalogados livros e vamos implementar o código da função de pesquisa. Por meio dela, um usuário deve ser capaz de realizar uma busca usando termos parciais tanto para título quanto para autor.
Vamos começar como deve começar qualquer código: pelos testes. Na nossa aplicação hipotética, o usuário poderá fazer uma busca na Home. Note que nesta aplicação já configuramos o root_path
para a index
do HomeController
.
require 'rails_helper'
feature 'Visit home page' do
context 'and search for book' do
scenario 'successfully' do
Book.create(title: 'Animal Farm', author: 'George Orwell')
Book.create(title: 'Battle Royale', author: 'Koushun Takami')
Book.create(title: 'A to Z Mysteries', author: 'Ron Roy')
visit root_path
fill_in 'Busca:', with: 'Roy'
click_on 'Pesquisar'
expect(current_path).to eq search_path
expect(page).to have_content('Battle Royale')
expect(page).to have_content('Koushun Takami')
expect(page).to have_content('A to Z Mysteries')
expect(page).to have_content('Ron Roy')
expect(page).not_to have_content('George Orwell')
expect(page).not_to have_content('Animal Farm')
end
end
end
Nos testes acima são criadas instâncias da classe Book
e, após preencher o formulário e clicar no botão "Pesquisar", avaliamos se na página de resultados são renderizados os resultados corretamente. Garantimos nos testes que tanto atributo author
quanto title
sejam contemplados na funcionalidade. Com essa estrutura de código, sabemos que o primeiro erro que será levantado quando executarmos o comando rspec
nos avisará que não existe a classe Book
. Para isso, podemos rodar o comando:
$ rails generate model book author:string title:string
Agora precisamos criar o formulário de pesquisa, que nesta aplicação se encontra na Home, ou seja, adicionamos no arquivo app/views/home/index.html.erb
o código a seguir:
<h1> Bem vindo </h1>
<%= form_with url: search_path, method: :get do %>
<%= label_tag :q, 'Busca:' %>
<%= text_field_tag :q %>
<%= submit_tag 'Pesquisar' %>
<% end %>
Em Ruby on Rails existe mais de uma maneira de montar formulários. Aqui optamos por usar o método form_with
para montar os campos HTML necessários. Perceba que url
recebe a rota search_path
para qual os parâmetro q
(abreviação do inglês "query") será encaminhado. O label_tag
e o text_field_tag
compõem o campo que receberá o texto a ser pesquisado e armazenado na variável que chamamos de q
. O submit_tag
compõe o botão que desencadeará a ação de pesquisa enviando o texto pesquisado e armazenado no parâmetro q
para a rota search_path
. Dessa maneira, sabemos que será necessário modificar nosso arquivo de rotas routes.rb
:
Rails.application.routes.draw do
root to: "home#index"
get 'search', to:"home#search"
end
A rota search_path
é um get
que direciona os parâmetros do formulário para a action search
no HomeController
:
class HomeController < ApplicationController
def index;end
def search
@books = Book.where('title like ? OR author like ?',
"%#{params[:q]}%", "%#{params[:q]}%")
end
end
O código na action search
monta um array com todos os objetos da classe Book
que correspondem ao valor da pesquisa. Nessa consulta ao banco utilizamos o marcador %
para indicar que procuramos valores que contém o termo buscado. Para conhecer mais sobre marcadores, recomendamos esta documentação. Assim, query do código acima realiza uma busca parcial, ou seja, serão retornados como verdadeiros os resultados com correspondência parcial do termo pesquisado. Caso você queria que os resultados retornados sejam exatos, basta remover os marcadores deixando seu código da query assim:
def search
@books = Book.where('title = ? OR author = ?',
params[:q], params[:q])
end
Note que aqui ainda estamos buscando em ambos os atributos da classe Book
, no entanto, agora só serão retornados resultados com correspondência exata do termo pesquisado.
Nos resta agora apresentar os livros encontrados na página de resultados em app/views/home/search.html.erb
:
<h1>Resultados da busca</h1>
<ul>
<% @books.each do |book| %>
<li><%= book.title %>, <%= book.author %></li>
<% end %>
</ul>
O código acima itera pelo array @books
que contém os resultados da query e gera para cada item uma tag <li>
com o título e o autor do livro no HTML final da página.
Considerações finais
Neste tutorial passamos pelo processo inicial de construção de um formulário de pesquisa simples em Ruby on Rails utilizando Test Driven Development. Ainda são necessários mais testes para garantir, por exemplo, que alguma mensagem seja renderizada em tela caso não sejam encontrados resultados, entre outras características que possam ser importantes. Além disso, na minha opinião, search_path
deveria ser uma rota aninhada parte de resources
de books
. Aqui a implementamos como parte de home
apenas para demonstração, você deve avaliar o que faz mais sentido para sua aplicação.