Coleção Ruby/Rails para coleção
-
09-06-2019 - |
Pergunta
Eu tenho duas tabelas unidas a uma tabela de junção - isso é apenas pseudocódigo:
Library
Book
LibraryBooks
O que preciso fazer é se eu tiver o id de uma biblioteca, quero obter todas as bibliotecas em que estão todos os livros que esta biblioteca possui.
Então, se eu tenho a Biblioteca 1, e a Biblioteca 1 contém os livros A e B, e os livros A e B estão nas Bibliotecas 1, 2 e 3, existe uma maneira elegante (uma linha) de fazer isso no Rails?
Eu estava pensando:
l = Library.find(1)
allLibraries = l.books.libraries
Mas isso não parece funcionar.Sugestões?
Solução
l = Library.find(:all, :include => :books)
l.books.map { |b| b.library_ids }.flatten.uniq
Observe que map(&:library_ids)
é mais lento que map { |b| b.library_ids }
no Ruby 1.8.6 e mais rápido no 1.9.0.
Devo também mencionar que se você usou :joins
em vez de include
lá, ele encontraria a biblioteca e os livros relacionados, todos na mesma consulta, acelerando o tempo do banco de dados. :joins
entretanto, só funcionará se uma biblioteca tiver livros.
Outras dicas
Talvez:
l.books.map {|b| b.libraries}
ou
l.books.map {|b| b.libraries}.flatten.uniq
se você quiser tudo em uma matriz plana.
Claro, você realmente deve definir isso como um método na Biblioteca, de modo a defender a nobre causa do encapsulamento.
Se você deseja que uma matriz unidimensional de bibliotecas seja retornada, com as duplicatas removidas.
l.books.map{|b| b.libraries}.flatten.uniq
Um problema com
l.books.map{|b| b.libraries}.flatten.uniq
é que ele irá gerar uma chamada SQL para cada livro em l.Uma abordagem melhor (supondo que eu entenda seu esquema) pode ser:
LibraryBook.find(:all, :conditions => ['book_id IN (?)', l.book_ids]).map(&:library_id).uniq