Adding new entity
Today we will work on extending Shyshka application with the possibility of adding examples to the words. To each word we will be able to add as many examples of usages as we wish.
What are associations?
In simple words, associations model relationships between entities. In our case, our one entity will be Word and the second one will be Example. Each Word can have many Examples but every Example can have only one Word associated to it.
Associations in Hanami
Since associations represents how data is linked in the database, we define associations in repositories.
Unlike associations in Ruby on Rails framework, associations does not add any public method to the repository. Instead, Hanami prefers explicit interface - which means that if we want to perform specific action, like adding word with examples, we need to explicitly add method to perform this operation. This design choice is supposed to prevent repositories from having extensive and mostly unused public API.
Another difference between Ruby on Rails and Hanami associations is lacking of eager loading - if we want to load a Word with associated Examples we have to add additional method to do it. If we don’t add this method, then the result of the association will be nil
.
Adding has_many
association
The first we need to do is creating a new entity called Example.
bundle exec hanami generate migration create_examples
Open newly created migration file and add this code:
Hanami::Model.migration do
change do
create_table :examples do
primary_key :id
foreign_key :word_id, :words, on_delete: :cascade, null: false
column :text, String, null: false
column :created_at, DateTime, null: false
column :updated_at, DateTime, null: false
end
end
end
Most of the code above is familiar - we define a new table called examples, set primary_key and some columns. The new thing here is foreign_key - we specify here a column that will link Example with a Word. By setting on_delete: :cascade
we define how this entry should behave when associated Word will be deleted - in our case we want to delete Examples as well.
To run the migration type in the console:
bundle exec hanami db prepare
Now, let’s generate Example model. We will do this by typing:
bundle exec hanami generate model example
Next, let’s open WordRepository
and define the association with Example here:
class WordRepository < Hanami::Repository
associations do
has_many :examples
end
def create_with_examples(data)
assoc(:examples).create(data)
end
def add_example(word, data)
assoc(:examples, word).add(data)
end
def find_with_examples(id)
aggregate(:examples).where(id: id).as(Word).one
end
end
We have defined a has_many
association between Word and Example models and we have added three new methods:
create_with_examples
for creating Word with Example at one goadd_example
for adding Example to an existing Wordfind_with_examples
for retrieving Word with all Examples preloaded
Summary
Today we’ve stepped out of basic CRUD app and we’ve extended our app with the first association. In the next post, we will prepare our frontend for adding and displaying words with associated examples.
Written on May 8, 2017