Ruby / Rails Collection à Collection
-
09-06-2019 - |
Question
J'ai deux tables jointes à une table de jointure - il ne s'agit que de pseudo-code:
Library
Book
LibraryBooks
Ce que je dois faire, c'est que si j'ai l'identifiant d'une bibliothèque, je veux obtenir toutes les bibliothèques contenant tous les livres de cette bibliothèque.
Donc, si j'ai la bibliothèque 1 et que la bibliothèque 1 contient les livres A et B, et que les livres A et B se trouvent dans les bibliothèques 1, 2 et 3, existe-t-il un moyen élégant (une ligne) de le faire dans les rails?
Je pensais:
l = Library.find(1)
allLibraries = l.books.libraries
Mais cela ne semble pas fonctionner. Suggestions?
La solution
l = Library.find(:all, :include => :books)
l.books.map { |b| b.library_ids }.flatten.uniq
Notez que map (& amp;: library_ids)
est plus lent que map {| b | b.library_ids}
dans Ruby 1.8.6, et plus rapide dans 1.9.0.
Je devrais également mentionner que si vous utilisiez : joint
au lieu de include
, la bibliothèque et les livres associés seraient tous trouvés dans la même requête, ce qui accélèrerait le temps de la base de données. . : join
ne fonctionnera que si une bibliothèque a des livres.
Autres conseils
Peut-être:
l.books.map {|b| b.libraries}
ou
l.books.map {|b| b.libraries}.flatten.uniq
si vous voulez tout cela dans un tableau plat.
Bien sûr, vous devriez définir cela comme une méthode sur Library, afin de défendre la noble cause de l'encapsulation.
Si vous souhaitez obtenir un tableau unidimensionnel de bibliothèques, en supprimant les doublons.
l.books.map{|b| b.libraries}.flatten.uniq
Un problème avec
l.books.map{|b| b.libraries}.flatten.uniq
est que cela va générer un appel SQL pour chaque livre dans l. Une meilleure approche (si je comprends votre schéma) pourrait être:
LibraryBook.find(:all, :conditions => ['book_id IN (?)', l.book_ids]).map(&:library_id).uniq