2016-05-24 2 views
1

私は、ユーザーが視聴している番組や視聴している番組を選択できるRailsアプリケーションを持っています。 ActiveRecordの団体は、多少のようになります。アクティブレコード:同じ親に属する異なるアソシエーションを照会します

class User 
    has_many :episodes_joins, :dependent => :delete_all, class_name: 'UsersEpisodesJoin' 
    has_many :episodes, through: :episodes_joins 
    has_many :shows_joins, :dependent => :delete_all, class_name: 'UsersShowsJoin' 
    has_many :shows, through: :shows_joins 
end 

class Show 
    has_many :episodes, dependent: :destroy 
    has_many :users_shows_joins, :dependent => :delete_all 
    has_many :users, through: :users_shows_joins 
end 

class Episode 
    belongs_to :show 
    has_many :users_episodes_joins, :dependent => :delete_all 
    has_many :users, through: :users_episodes_joins 
end 

class UsersShowsJoin 
    belongs_to :user 
    belongs_to :show 
end 

class UsersEpisodesJoin 
    belongs_to :user 
    belongs_to :episode 
end 

私は、ユーザーがそれぞれのために「特別なエピソードを」フィルタリングする許可したい(?「特別なエピソードは」trueに設定さepisode.specialを持っている)、個別に表示されます。このため、私はfilter_specialsという名前のUsersShowsJoinsテーブルにブール値の列を追加することを考えていました。私は今、このような何かをしたい:

episodes = user.episodes.where(special: false).to_a 
user.episodes.where(special: true) do |epi| 
    show_join = UsersShowsJoins.where(user_id: user.id, show_id: epi.show.id).first 
    episodes << epi if show_join.nil? || !show_join.filter_specials? 
end 
# do something with 'episodes', 
# which contains all non-special episodes, 
# as well as special episodes of shows for which the user is not filtering these 

可能性も、私はこれはDBクエリのトンを行います非常にハックと遅い実装である知っている、と私はそれを行うにはもっと良い方法があります確信しています1つのクエリで

さらに、ユーザーが選択したすべての番組をDBに照会して、同じユーザーのUsersEpisodesJoins行を持つ対応するエピソードをあらかじめロードしたいと考えています。何かのように:私は複雑なクエリのためのN + 1の問題が発生しないように

shows = user.shows.all 
h = {} 
shows.each do |show| 
    episodes = user.episodes.where(show_id: show.id).all 
    h[show] = episodes 
end 

# do something with h, 
# which contains a user's watched episodes for each selected show 

にはどうすれば、効率的にこれらのクエリを書くことができますか?

答えて

2

あなたは、このようにフィルタリングする特別なエピソードを書くことができる必要があります:

show_joins = UsersShowsJoins.joins(:shows, :users).where(episodes: { special: true}) 

これは、彼らの共通の関係でshowsusersの両方に参加する、とtruespecialセットを持っているエピソードをフィルタリングします。

あなたが書くことができるバリエーションは、あなたが主な目的としてで作業したいオブジェクトの種類に基づいて、あります

shows = Show.joins(:users, :episodes).where(episodes: {special: true}) 

か:2番目のクエリのために

episodes = Episode.joins(shows: :users).where(special: true) 

、あなたはこれを使用できます:

これは、ユーザーが視聴している番組のエピソードをあらかじめロードする必要があります。あなたが選択した場合は、そのように、where条件、group -ing、とさえorder条件を追加することができます。

user.shows.includes(:episodes).order("shows.title") 

を(ショー・タイトル・フィールドがあると仮定して)ショーのタイトルで結果を注文します。

Active Record Query Interfaceガイドには、Joining Tablesセクションにいくつかの素晴らしい例があります。このような複雑なクエリを効率的に行う方法については、読んでおく価値があります。

+0

ありがとうございました!まさに私が必要としていたことですが、私はARのガイドを読んでいましたが、そのような詳細なJoining Tablesセクションがあることに気がつかなかったので、指摘していただきありがとうございます。 – rpinheiro

関連する問題