これは、ビデオ鑑賞への質問のフォローアップであるcodeschoolスコープ上に、同様にすることにより、ビデオを見クリス・オリバーをマージする方法について。
私がやろうとしているのは、利用可能なauthors
ものbook
が少なくとも1つあるものだけを見つけることです。次に、それらをフィルタリングした後authors
、それらの本に関するデータを引き出すたびにデータベースにクエリを実行したくないのでbooks
、選択しauthors
たものすべてを熱心にロードしたいと思います。私はいくつかの異なるスコープを試しましたが、どれも私が必要なものを正確に提供していません:
#app/models/book.rb
class Book < ActiveRecord::Base
belongs_to :author
scope :available, ->{where(availability: true)}
scope :unavailable, ->{where(availability: false)}
end
#app/models/author.rb
class Author < ActiveRecord::Base
has_many :books, dependent: :destroy
scope :with_available_books, ->{joins(:books).merge(Book.available)}
scope :with_available_books_uniq, ->{uniq.joins(:books).merge(Book.available)}
scope :with_available_books_includes, ->{joins(:books).merge(Book.available).includes(:books)}
scope :with_available_books_uniq_includes, ->{uniq.joins(:books).merge(Book.available).includes(:books)}
def to_s
self.name
end
end
これが私のデータベースにあるもののスナップショットです私は3つ 持っていますauthors
:
Neil
、および彼は合計10冊の関連書籍を持っており、すべてが利用可能ですJohn
、および彼は合計10冊の関連書籍を持っており、すべて利用できませんMixture Author
、彼は合計10冊の本を持っており、5冊は利用可能、5冊は利用不可ですすべてのクエリを実行し、結果をHTMLで出力しました。これが私が得ているものです:
# Duplicating the authors AND N + 1 problem with associated books
Author.with_available_books.size:15
本の著者[0]:10
本の著者[1]
:10
# Fixed the duplication but still N + 1 problem with the associated books
Author.with_available_books_uniq.size:
著者用の本2冊[0]:10
著者用の本[1]
:10
# Fixed the N + 1 problem but duplicating authors
Author.with_available_books_includes.size:15
# Fixed the duplication and fixed the N + 1 problem
# BUT now it is filtering out the unavailable books!
# But I want all the Books for these authors!
Author.with_available_books_uniq_includes.size:2
冊の著者[0]:10
冊の著者[1]
:5
重複していない著者のためにすべての本を入手するにはどうすればよいですか?関連付けられたオブジェクトの属性(本のavailable
属性)で作成者をフィルタリングし、それらの本を熱心にロードしたいと思います。
途方に感謝クリス・オリバー、この状況についての私の電子メールの問い合わせへの対応のための自分自身。
最初に著者をつかみます:
@uniq_authors_with_available_books = Author.with_available_books_uniq
これは適切につかみNeil
、Mixture Author
両方が利用可能な本を持っている人:
2.2.1 :004 > @authors_with_available_books.size
=> 2
ただし、以下に示すように、N + 1
これら2人の著者の本に関する情報を取得したい場合は、問題が依然として存在します。
2.2.1 :005 > @authors_with_available_books[0].books.size
(0.2ms) SELECT COUNT(*) FROM "books" WHERE "books"."author_id" = ? [["author_id", 1]]
=> 10
2.2.1 :006 > @authors_with_available_books[1].books.size
(0.2ms) SELECT COUNT(*) FROM "books" WHERE "books"."author_id" = ? [["author_id", 3]]
=> 10
クリスのアドバイスに感謝します。私たちがしなければならないのは、:からの 'subquery
を使用した本に対する個別のクエリです。id
@authors_with_available_books
2.2.1 :007 > @books_by_those_authors = Book.where(author_id: @authors_with_available_books.map(&:id))
Book Load (0.4ms) SELECT "books".* FROM "books" WHERE "books"."author_id" IN (1, 3)
SQLクエリから、id
が1
またはに等しい本のみを取得していることがわかります3
。最初のクエリでは、利用可能な本を持っているのはそれらの著者だけであることがわかったため、これらの著者を取得しているだけです。
今、私はこれを行うことができます:
@books.size
=> 20
これは、合計10Neil
冊の本と合計Mixture Author
10冊の本があり、合計でが得られるため、理にかなっています20
。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加