Отношение активной записи имеет много сквозных

У меня есть следующие модели:

class FavoriteDirectorSet < ActiveRecord::Base
  has_many :links
  has_many :directors, through: :links
end

class Link < ActiveRecord::Base
  belongs_to :favorite_director_set
  belongs_to :director
end

class Director < ActiveRecord::Base
  has_many :links
  has_many :favorite_director_sets, through: :links
  has_many :movies
end

class Movie < ActiveRecord::Base
  belongs_to :director
end

Я начал строить запросы, связывая области вместе, но я не понимаю, как это разбить. Как создать объект Active Record Relation для фильмов, которые соответствуют заданному идентификатору FavoriteDirectorSet?

ОБНОВИТЬ

У меня есть два рабочих решения («любимый_директор», сокращенно fd):

1) @rubyman вариант 1:

fd_sets = FDSet.find(:fd_set_id)
res = Movie.where('director_id IN (?)', fd_sets.directors.map(&:id))

2) @rubyman вариант 2:

res = Movie.joins(:director=>[:links=>:fd_set]).
    where("fd_sets.id = ?", :fd_set_id)

person Derek Hill    schedule 25.10.2012    source источник
comment
Разве вы не можете просто присоединиться к набору любимых режиссеров на Favorite_director_set.fk_director = movie.fk_director ?   -  person mkk    schedule 25.10.2012
comment
@мкк. Спасибо. Я думаю, что это имеет смысл, но я боюсь, что вам придется объяснить это для меня. то есть вы бы сказали Movie.joins(:what?)...   -  person Derek Hill    schedule 25.10.2012


Ответы (2)


Один из способов: fds = FavoriteDirectorSet.find(fds_id)

Movie.where('director_id IN (?)', fds.derectors.map(&:id))

ИЛИ с соединениями (не уверен в этом)

Movie.joins(:director=>[:links=>:favorite_director_sets]).where("favorite_director_sets.id = ?", fds_id)

person Rubyman    schedule 25.10.2012
comment
Спасибо. У меня оба работают. Пришлось сделать один твик на второй: [:links=›:favorite_director_set] (т.е. наборы не во множественном числе). Очень признателен. - person Derek Hill; 25.10.2012

Вы можете использовать JOIN в соответствии с RubyGuides.

Синтаксис, который я бы использовал:

@movie.joins("INNER JOIN favorite_director_sets ON favorite_director_sets.fk_director = movies.fk_director") # please ensure that table names are correct - if they follow convention, I believe they are correct

Теперь вы можете просто добавить условие where, то есть favorite_director_sets.id = ?, fds_id

Обратите внимание, что в вашем случае вы можете использовать что-то еще, кроме LINNER. На CoddingHorror есть отличные визуальное объяснение того, что означает INNER JOIN и какие есть альтернативы.

ОБНОВИТЬ:

Обратите внимание, что другое решение намного проще, но, вероятно, хуже с точки зрения производительности:

fds = FavoriteDirectorSet.find(fds_id)
@movies = fds.director.movies

или вы можете даже написать это в одну строку:

@movies = FavoriteDirectorSet.find(fds_id).director.movies

ОБНОВЛЕНИЕ: этот ответ неверен, потому что я забыл о таблице ссылок. Решение Rubyman выглядит нормально

person mkk    schedule 25.10.2012
comment
Спасибо за это. Я не мог заставить это решение работать, но мне интересно, не упустил ли я что-то. Это приводит к меньшему количеству SQL, поэтому мне интересно, есть ли более быстрый вариант, который мне не хватает. Я отредактировал свой вопрос. - person Derek Hill; 25.10.2012
comment
@ Дерек, извини, я неправильно понял вопрос - я забыл о таблице ссылок. Я считаю, что вы должны придерживаться решения Rubyman. - person mkk; 25.10.2012
comment
Без проблем. Но ты заставил меня задуматься ;-) - person Derek Hill; 25.10.2012