2008-09-17 21 views
6

Tengo un dos tablas unidas con una tabla de unión - esto es sólo pseudo-código:de Ruby Rails Colección/a Colección

Library 
Book 
LibraryBooks 

Lo que tengo que hacer es si tengo el id de una biblioteca, quiero para obtener todas las bibliotecas en las que están todos los libros que tiene esta biblioteca.

Así que si tengo la Biblioteca 1, y la Biblioteca 1 tiene los libros A y B, y los libros A y B están en las Bibliotecas 1, 2, y 3, ¿hay una forma elegante (una línea) de hacer esto en rieles?

que estaba pensando:

l = Library.find(1) 
allLibraries = l.books.libraries 

Pero eso no parece funcionar. Sugerencias?

+0

¿Deseas todas las bibliotecas que tienen libros? El fragmento de código anterior no devolvería la misma biblioteca que l. Es como preguntarle a todos sus libros, quién es su dueño. Usted. Un poco de confusión ... pero los de abajo harán el truco de colación. – Gishu

+0

Todas las bibliotecas que tienen libros que también están en esta biblioteca, ¿sí? –

+0

@Jim - eso es exactamente lo que quiero – aronchick

Respuesta

7
l = Library.find(:all, :include => :books) 
l.books.map { |b| b.library_ids }.flatten.uniq 

Tenga en cuenta que es más lento que map(&:library_ids)map { |b| b.library_ids } en Ruby 1.8.6, 1.9.0 y más rápido en.

Debo mencionar que si usaste :joins en lugar de include allí, encontraría la biblioteca y libros relacionados todos en la misma consulta, acelerando el tiempo de la base de datos. :joins solo funcionará, sin embargo, si una biblioteca tiene libros.

+0

la lentitud de Symbol # to_proc generalmente se ve superada por las llamadas a la base de datos. –

+0

No veo cómo podría funcionar esto. La primera línea devolverá una matriz de objetos Library (bueno, en realidad un proxy, pero con los mismos métodos). Esta matriz no tendrá un método de "libros", por lo que la línea dos fallará, ¿no? – MiniQuark

3

Tal vez:

l.books.map {|b| b.libraries} 

o

l.books.map {|b| b.libraries}.flatten.uniq 

si lo quieres todo en una matriz plana.

Por supuesto, realmente debe definir esto como un método en la Biblioteca, a fin de mantener la noble causa de la encapsulación.

2

Si desea que se devuelva una matriz unidimensional de bibliotecas, con duplicados eliminados.

l.books.map{|b| b.libraries}.flatten.uniq 
2

Un problema con

l.books.map{|b| b.libraries}.flatten.uniq 

es que va a generar una llamada de SQL para cada libro en l. Un mejor enfoque (suponiendo que entiendo su esquema) podría ser:

LibraryBook.find(:all, :conditions => ['book_id IN (?)', l.book_ids]).map(&:library_id).uniq 
+0

Esto no es estrictamente cierto, dependiendo de lo que se haya cargado inicialmente. –

+0

lo siento, debería haber dejado eso en claro: supongo que no has precargado nada más que l (la biblioteca inicial) –

+0

uy ... no estoy seguro de que esto funcione ... ¿te refieres a LibraryBook o Library? – aronchick