Edit the migrations:
# db/migrations/20171024083639_create_users.rb
Hanami::Model.migration do
change do
create_table :users 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/20171024083725_create_avatars.rb
Hanami::Model.migration do
change do
create_table :avatars do
primary_key :id
foreign_key :user_id, :users, null: false, on_delete: :cascade
column :url, String, null: false
column :created_at, DateTime, null: false
end
end
Now we can prepare the database:
# lib/bookshelf/repositories/user_repository.rb
class UserRepository < Hanami::Repository
associations do
has_one :avatar
end
def create_with_avatar(data)
assoc(:avatar).create(data)
end
def find_with_avatar(id)
aggregate(:avatar).where(id: id).map_to(User).one
end
end
We have defined only for the operations that we need for our model domain. In this way, we avoid to bloat UserRepository
with dozen of unneeded methods.
Let’s create an user with an avatar single database operation:
repository = UserRepository.new
user = repository.create_with_avatar(name: "Luca", avatar: { url: "https://avatars.test/luca.png" })
# => #<User:0x00007fa166ac8550 @attributes={:id=>1, :name=>"Luca", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC, :avatar=>#<Avatar:0x00007fa166ac35c8 @attributes={:id=>1, :user_id=>1, :url=>"https://avatars.test/luca.png", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC}>}>
user.id
# => 1
user.name
user.avatar
Because we haven’t explicitly loaded the associated record, user.avatar
is nil
. We can use the method that we have defined on before (#find_with_avatar
):
user = repository.find_with_avatar(user.id)
# => #<User:0x00007fa166a71048 @attributes={:id=>1, :name=>"Luca", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC, :avatar=>#<Avatar:0x00007fa166a70328 @attributes={:id=>1, :user_id=>1, :url=>"https://avatars.test/luca.png", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC}>}>
user.avatar
# => #<Avatar:0x00007fa166a70328 @attributes={:id=>1, :user_id=>1, :url=>"https://avatars.test/luca.png", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC}>
This time user.avatar
has the associated avatar.
# lib/bookshelf/repositories/user_repository.rb
class UserRepository < Hanami::Repository
# ...
def add_avatar(user, data)
assoc(:avatar, user).add(data)
end
def remove_avatar(user)
assoc(:avatar, user).delete
end
def update_avatar(user, data)
assoc(:avatar, user).update(data)
end
def replace_avatar(user, data)
assoc(:avatar, user).replace(data)
end