使用包含Rails

时间:2015-06-30 15:25:18

标签: ruby-on-rails ruby activerecord merge eager-loading

这是关于在codeschool观看视频的视频,以及通过合并方法Chris Oliver观看视频的后续问题。

我要做的只是查找至少有一个authors可用的book。然后在对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

以下是我的数据库中的内容的快照 我有 authors

  1. Neil,他共有10本相关书籍,所有可用
  2. John,他共有10本相关图书,所有资料不可用
  3. Mixture Author,他共有10本书, 5个可用,5个不可用
  4. 我运行了所有查询并以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属性)过滤作者,我想热切地加载这些书。

1 个答案:

答案 0 :(得分:0)

非常感谢Chris Oliver自己回复我关于此情况的电子邮件查询。

首先抓住作者:

@uniq_authors_with_available_books = Author.with_available_books_uniq

这可以正确地抓住两个都有可用图书的NeilMixture Author

2.2.1 :004 > @authors_with_available_books.size
=> 2 

但是,如下所示,如果我们想要获取有关这两位作者的任何信息,N + 1问题仍然存在。书:

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等于13的图书。它只是抓住那些作者,因为第一个问题告诉我们只有那些作者才有可用的书籍。

现在我可以这样做:

@books.size
=> 20 

这是有道理的,因为Neil总共有10本书,Mixture Author总共有10本书,总共合计20