您如何分组并仅列出父对象的某些关联对象?

How can you group and list only certain associated objects of the father object?

我在两个模型之间有一个简单的has_many关联:

class Author < ActiveRecord::Base
  has_many :books
end

class Book < ActiveRecord::Base
  belongs_to :author
end

假设我有一组书籍对象。

[#<Book:0x00007fbe329ff6f8
  id: 10,
  name: "book_15"
  author_id: 1>,
 #<Book:0x00007fbe329ff6f9
  id: 15,
  name: "Bible"
  author_id: nil>,
 #<Book:0x00007fbe329ff6f1
  id: 17
  name: "book_45"
  author_id: 1>]

如何将此对象数组转换为 json 对象数组,以便顶层将作者及其相关书籍显示为数组,而没有作者的书籍也在第一级独立。

像这样:

[
  {
    author_id,
    author_name,
    books: [
      { ...book json... },
      { ...book json... },
    ]
  },
  { ...book json ... },
  { ...book json ... }
]

在我的特定示例中,结果如下所示:

[
  {
    id: 1,
    name: "Dexter Willis",
    books: [
      { id: 10, name: "book_15" },
      { id: 17, name: "book_45" }
    ]
  },
  { id: 15, name: "Bible" }
]

如何做到这一点?提前致谢。

假设 books 是一组书籍对象:

 books_with_author, books_without_author = books.partition { |book| book.author_id }
 books_grouped_by_author = books_with_author.group_by(&:author_id)
 # to avoid N+1
 authors = Author.where(id: books_grouped_by_author.keys)

 books_with_author = books_grouped_by_author.map do |author_id, author_books|
   author = authors.detect { |a| a.id == author_id }
   
   {
     id: author.id,
     name: author.name,
     books: author_books.map { |book| { id: book.id, name: book.name } }
   }
 end

 books_without_author = books_without_author.map { |book| { id: book.id, name: book.name } }

 books_with_author.push(*books_without_author)