Screencast – Buscas e Rails primeira parte
Olá a todos. Já estava na hora de lançar este screencast (a quase um mês venho prometendo).
Efetuar buscas em modelos é algo que com ActiveRecord se tornou super fácil mas relacionar objetos e buscar em vários locais é um problema para quem está começando. Tentarei em três episódios mostrar como fazer buscas em seus conteúdos gravados no banco de dados de maneira simples.
O primeiro episódio será baseado em consultas no banco de dados, o que é uma solução um tanto quanto antiga, mas resolve para pequenas aplicações sem grande complexidade. A idéia em si pode ser utilizada de outras maneiras por isto achei interessante expor a mesma.
Código-fonte com aplicação pronta
Código-fonte com aplicação em fase inicial
Resumo em texto:
Criar model de buscas
rails g model Busca texto:string objeto_id:integer objeto_classe:string
rake db:migrate
Configurar observers
# config/application.rb
config.active_record.observers = :buscas_observer
Callbacks dos observers
# app/observers/buscas_observer.rb
class BuscasObserver < ActiveRecord::Observer
observe :post, :foto
def after_create(objeto)
criar_busca(objeto)
end
def after_update(objeto)
if Busca.where(hash_comum(objeto)).exists?
busca = Busca.where(hash_comum(objeto)).first
busca.update_attribute(:texto, unir_texto(objeto))
else
criar_busca(objeto)
end
end
def after_destroy(objeto)
Busca.where(hash_comum(objeto)).delete
end
def hash_comum(objeto)
{:objeto_id => objeto.id, :objeto_classe => objeto.class.to_s}
end
def unir_texto(objeto)
objeto.attributes.find_all{|t,v| v.is_a?(String)}.collect{|t,v| v}.join(' ')
end
def criar_busca(objeto)
Busca.create!(hash_comum(objeto).merge(:texto => unir_texto(objeto)))
end
end
Gerar novamente o índice para models existentes
Foto.all.each{|t| t.update_attribute(:updated_at, Time.now)}
Post.all.each{|t| t.update_attribute(:updated_at, Time.now)}
Criar o método de cast
# app/models/busca.rb
default_scope :order => "created_at DESC"
def cast
Kernel.const_get(objeto_classe).find(objeto_id)
end
Ajustar controller de busca
# app/controllers/buscas_controller.rb
def index
busca = params[:busca].to_s
@resultados = Busca.where("texto LIKE ?","%#{busca}%")
end
Ajustar index de buscas
# app/views/buscas/index.html.erb
<% @resultados.each do |resultado|%>
<% objeto = resultado.cast%>
<%=objeto.titulo%>
<%=truncate objeto.texto, :length => 200%>
<%=link_to 'ver', objeto%>
<% end %>