Edit the migrations:
# db/migrations/20171024081558_create_authors.rb
Hanami::Model.migration do
change do
create_table :authors do
primary_key :id
column :name, String, null: false
column :created_at, DateTime, null: false
column :updated_at, DateTime, null: false
end
end
end
# db/migrations/20171024081617_create_books.rb
Hanami::Model.migration do
change do
create_table :books do
primary_key :id
foreign_key :author_id, :authors, on_delete: :cascade
column :title, String, null: false
column :created_at, DateTime, null: false
column :updated_at, DateTime, null: false
end
end
Now we can prepare the database:
$ bundle exec hanami db prepare
Let’s edit AuthorRepository
with the following code:
Let’s create an author with a collection of books with a single database operation:
repository = AuthorRepository.new
author = repository.create_with_books(name: "Alexandre Dumas", books: [{title: "The Count of Montecristo"}])
# => #<Author:0x007f811c415420 @attributes={:id=>1, :name=>"Alexandre Dumas", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC, :books=>[#<Book:0x007f811c40fe08 @attributes={:id=>1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]}>
author.id
# => 1
author.name
# => "Alexandre Dumas"
author.books
# => [#<Book:0x007f811c40fe08 @attributes={:id=>1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]
What happens if we load the author with AuthorRepository#find
?
author = repository.find(author.id)
# => #<Author:0x007f811b6237e0 @attributes={:id=>1, :name=>"Alexandre Dumas", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>
author.books
# => nil
Because we haven’t explicitly loaded the associated records, author.books
is nil
. We can use the method that we have defined on before (#find_with_books
):
author = repository.find_with_books(author.id)
# => #<Author:0x007f811bbeb6f0 @attributes={:id=>1, :name=>"Alexandre Dumas", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC, :books=>[#<Book:0x007f811bbea430 @attributes={:id=>1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]}>
# => [#<Book:0x007f811bbea430 @attributes={:id=>1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]
What if we need to add or remove books from an author? We need to define new methods to do so.
Let’s add a book:
book = repository.add_book(author, title: "The Three Musketeers")
And remove it:
repository.remove_book(author, book.id)
# lib/bookshelf/repositories/author_repository.rb
class AuthorRepository < Hanami::Repository
# ...
def books_count(author)
assoc(:books, author).count
end
def on_sales_books_count(author)
assoc(:books, author).where(on_sale: true).count
end
def book_exists?(author, id)
book_for(author, id).exists?
end
private
def book_for(author, id)
assoc(:books, author).where(id: id)
end
You can also run operations on top of these scopes: