У меня есть две таблицы, соединенные с таблицей соединений - это просто псевдокод:
Library
Book
LibraryBooks
Что мне нужно сделать, так это если у меня есть идентификатор библиотеки, я хочу получить все библиотеки, в которых есть все книги, которые есть в этой библиотеке.
Итак, если у меня есть библиотека 1, а в библиотеке 1 есть книги A и B, а книги A и B находятся в библиотеках 1, 2 и 3, есть ли элегантный (однострочный) способ сделать это в рельсах?
Я подумал:
l = Library.find(1)
allLibraries = l.books.libraries
Но, похоже, это не работает. Предложения?
Во всех библиотеках есть книги, которые тоже есть в этой библиотеке, да?
@ Джим - это именно то, что я хочу





Возможно:
l.books.map {|b| b.libraries}
или же
l.books.map {|b| b.libraries}.flatten.uniq
если вы хотите все это в виде плоского массива.
Конечно, вы действительно должны определить это как метод в библиотеке, чтобы поддержать благородную причину инкапсуляции.
Если вы хотите получить одномерный массив библиотек с удаленными дубликатами.
l.books.map{|b| b.libraries}.flatten.uniq
Одна проблема с
l.books.map{|b| b.libraries}.flatten.uniq
заключается в том, что он будет генерировать один вызов SQL для каждой книги в l. Лучшим подходом (при условии, что я понимаю вашу схему) может быть:
LibraryBook.find(:all, :conditions => ['book_id IN (?)', l.book_ids]).map(&:library_id).uniq
Это не совсем так, в зависимости от того, что было загружено изначально.
извините, я должен был прояснить это: я предполагаю, что вы не загружали ничего, кроме l (исходная библиотека)
упс ... не уверен, что это работает ... вы имели в виду LibraryBook или Library?
l = Library.find(:all, :include => :books)
l.books.map { |b| b.library_ids }.flatten.uniq
Обратите внимание, что map(&:library_ids) медленнее, чем map { |b| b.library_ids } в Ruby 1.8.6 и быстрее в 1.9.0.
Я также должен упомянуть, что если бы вы использовали :joins вместо include, он обнаружил бы библиотеку и связанные книги в одном запросе, что ускорило бы время работы с базой данных. Однако :joins будет работать только в том случае, если в библиотеке есть книги.
медленность Symbol # to_proc обычно перевешивается вызовами базы данных.
Я не понимаю, как это могло работать. Первая строка вернет массив объектов библиотеки (на самом деле прокси, но с теми же методами). В этом массиве не будет метода "книги", поэтому вторая строка не удастся, не так ли?
Итак, вы хотите, чтобы во всех библиотеках были книги? Приведенный выше фрагмент кода не будет возвращать ту же библиотеку, что и l. Это все равно, что спрашивать у всех ваших книг, кто их владелец. Небольшая путаница ... но ответ Джима ниже подойдет для трюка с сопоставлением.