Alguns posts aqui no blog já exemplificaram como funcionam as associações na camada de modelo do Rails com ActiveRecord e como efetuar alguma pesquisa (query) a partir de algum modelo. Neste post vou demonstrar como combinar as duas coisas, efetuando filtros a partir de uma associação, usando tanto recurso de blocos quanto de mixins com módulos, também já abordados em posts anteriores.
Vou utilizar os mesmos modelos aqueles de Pessoa, Livro e Leitura:
class Pessoa < ActiveRecord::Base attr_accessible :nome, :idade has_many :leituras has_many :livros, through: :leituras end
class Livro < ActiveRecord::Base attr_accessible :titulo has_many :leituras has_many :leitores, through: :leituras, source: :pessoa end
class Leitura < ActiveRecord::Base attr_accessible :livro_id, :pessoa_id belongs_to :pessoa belongs_to :livro end
Ao buscar a lista de leitores de um livro, intuitivamente espera-se um Array, porém, em vez de retornar um Array com todos os objetos resultantes, o Rails retorna uma instância de um proxy próprio, que já nos possibilita invocar diretamente na associação alguns métodos como o create, que delega a chamada ao create do respectivo modelo da associação:
novo_leitor = livro.leitores.create(nome: "Daniel")
Além de create, as associações em Rails nos permitem invocar outros métodos como count, clear, etc. Mas e se quisermos invocar um método dessa forma?
leitores_criancas = livro.leitores.criancas
Há duas opções. A primeira é utilizar Mixins definindo em um módulo separado as queries personalizadas de que desejamos dispor e estendendo nossa associação com ele:
module FiltroLeitor def criancas where('idade < 10') end end
require "filtro_leitor" class Livro < ActiveRecord::Base attr_accessible :titulo has_many :leituras has_many :leitores, through: :leituras, source: :pessoa, extend: FiltroLeitor end
Uma vantagem desta primeira opção é que a associação leitores fica menos poluída, especialmente se vários métodos de pesquisa forem definidos.
E a segunda opção é adicionar um bloco à associação:
class Livro < ActiveRecord::Base attr_accessible :titulo has_many :leituras has_many :leitores, through: :leituras, source: :pessoa do def criancas where('idade < 10') end end end
Com a primeira ou a segunda opção, poderemos testar rodando os seguintes comandos no rails console:
# Primeiro criamos o livro livro = Livro.create(titulo: "Meu pé de laranja lima") # Adicionamos quatro leitores, sendo dois crianças livro.leitores.create(nome:"Daniel", idade: 27) # eu livro.leitores.create(nome:"Juliana", idade: 26) # patroa livro.leitores.create(nome:"Isabela", idade: 5) # sobrinha livro.leitores.create(nome:"Samuel", idade: 2) # sobrinho superdotado livro.leitores.count # Retorna 4 livro.leitores.criancas.count # Retorna 2
Recurso muito interessante e bem útil!
Até a próxima!
Nenhum comentário:
Postar um comentário