I have a simple has_many association between the two models:
class Author < ActiveRecord::Base
has_many :books
end
class Book < ActiveRecord::Base
belongs_to :author
end
Suppose I have an array of books objects.
[#<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>]
How can I convert this array of objects to an array of json objects, so that the top level shows the authors with their associated books as an array and books with no authors are also on the 1st level independently.
Like so:
[
{
author_id,
author_name,
books: [
{ ...book json... },
{ ...book json... },
]
},
{ ...book json ... },
{ ...book json ... }
]
In my particular example, the result would be something like below:
[
{
id: 1,
name: "Dexter Willis",
books: [
{ id: 10, name: "book_15" },
{ id: 17, name: "book_45" }
]
},
{ id: 15, name: "Bible" }
]
How can this be done? Thanks in advance.
CodePudding user response:
Assuming books
is an array of books objects:
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)