2014-12-10 1 views
3

Использование Rails 4.1.6 и Ruby, 2.1.2 и данные следующие три объекта:рельсов 4 сохраняющего порядок соединения объекта при использовании включает в has_many через ассоциацию

class FilmCollection 
    has_many :film_collection_films, -> { order(:position) } 
    has_many :films, through: :film_collection_films 
end 

class FilmCollectionFilm 
    belongs_to :film_collection_film 
    belongs_to :film 
end 

class Film 
    has_many :film_collection_films 
end 

FilmCollections являются коллекциями фильмов, и его членов представлены через объект объединения FilmCollectionFilm. FilmCollectionFilm имеет столбец для позиции, так что данный член коллекции может быть переупорядочен (думаю, как очередь фильма), и поэтому нам нужен объект join, а не has_and_belongs_to_many.

Моя проблема возникает, когда я стараюсь загружать фильмы нескольких коллекций сразу.

FilmCollection.first.films Вызов получит мне запрос, который выглядит следующим образом:

SELECT `film_collections`.* FROM `film_collections` 
    ORDER BY `film_collections`.`id` ASC LIMIT 1 
SELECT `films`.* FROM `films` 
    INNER JOIN `film_collection_films` ON `films`.`id` = `film_collection_films`.`film_id` 
    WHERE `film_collection_films`.`extensional_film_collection_id` = 1 
    ORDER BY `film_collection_films`.`position` ASC 

Заказов фильмы правильно на основе положения в соединении объекта.

Но вместо вызова FilmCollection.includes (: фильмы) .first.films получите мне следующий запрос:

SELECT `film_collections`.* FROM `film_collections` 
    ORDER BY `film_collections`.`id` ASC LIMIT 1 
SELECT `film_collection_films`.* FROM `film_collection_films` 
    WHERE `film_collection_films`.`film_collection_id` IN (1) 
    ORDER BY `film_collection_films`.`position` ASC 
SELECT `films`.* FROM `films` WHERE `films`.`id` IN (1, 16, 53, 185) 

который собирает правильные фильмы, но не принимает во внимание порядок во второй части запроса. Как я могу сохранить упорядочение соответствующего объекта соединения при активной загрузке с .includes(), но все еще не имеет запроса n + 1?

+0

Вместо этого используйте 'joins':' FilmCollection.joins (: films) .first.films'? – Surya

+0

Я действительно нашел решение, которое я собираюсь опубликовать. Это может сработать, но я считаю, что объединение в целом медленнее, чем в любом случае, особенно для больших таблиц. Хотя я мог ошибаться. – BitPuncher

+0

Примечание: Мне кажется, что это ошибка, которая будет исправлена ​​только в Rails 5:/https://github.com/rails/rails/pull/18766 –

ответ

2

Оказывается, вы можете решить эту проблему, явно включив в нее объект объединения, а также ассоциацию, которая через него. Строка ниже выберет все правильно и сохранит любые условные обозначения/порядок, присутствующие на объекте соединения.

FilmCollection.includes(film_collection_films: :film) 

Если вы только FilmCollection.includes(:films) то подберет FilmCollectionFilms так или иначе, а затем просто выбросить их. Таким образом, приведенный выше код будет работать с одинаковым объемом работы, но правильно построит запрос.

+1

Работает с рельсами 3.2. Я также хочу отметить, что сами sql-запросы для 'FilmCollection.includes (film_collection_films:: film)' и 'FilmCollection.includes (: films)' ** идентичны ** (проверены с .to_sql). Таким образом, мое обоснованное предположение о сохранении порядка (без копания в коде activerecord) осуществляется методом ruby ​​** sort ** после выполнения запросов и создания массивов. Это может привести к поражению производительности в зависимости от общего количества записей. Но для моих нужд это прекрасно! – mkralla11

 Смежные вопросы

  • Нет связанных вопросов^_^