This document explains how to use EAD(Entity Association Diagram).
After reading this document, you will know:
- How to generate basic associations for Ruby on Rails
- How to add STI model
EAD supports five types of associations:
In the remainder of this documentation, you'll learn how to declare and use the various forms of associations. But first, a quick introduction to the situations where each association type is appropriate.
belongs_to association is added automatically.
For example, if each supplier in your application has only one account, you'd declare the supplier model like this:
class Supplier < ApplicationRecord
has_one :account
end
class Account < ApplicationRecord
belongs_to :supplier
end
The corresponding migration might look like this:
class CreateSuppliers < ActiveRecord::Migration[7.0]
def change
create_table :suppliers do |t|
t.string :name
t.timestamps
end
end
end
class CreateAccounts < ActiveRecord::Migration[7.0]
def change
create_table :accounts do |t|
t.string :account_number
t.timestamps
end
end
end
class AddSupplierRefToAccount < ActiveRecord::Migration[7.0]
def change
add_reference :accounts, :supplier, null: false, foreign_key: true
end
end
For example, in an application containing authors and books, the author model could be declared like this:
class Author < ApplicationRecord
has_many :books
end
class Book < ApplicationRecord
belongs_to :author
end
The corresponding migration might look like this:
class CreateAuthors < ActiveRecord::Migration[7.0]
def change
create_table :authors do |t|
t.string :name
t.timestamps
end
end
end
class CreateBooks < ActiveRecord::Migration[7.0]
def change
create_table :books do |t|
t.datetime :published_at
t.timestamps
end
end
end
class AddAuthorRefToBook < ActiveRecord::Migration[7.0]
def change
add_reference :books, :author, null: false, foreign_key: true
end
end
For example, consider a medical practice where patients make appointments to see physicians. The relevant association declarations could look like this:
class Physician < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :physician
belongs_to :patient
end
class Patient < ApplicationRecord
has_many :appointments
has_many :physicians, through: :appointments
end
The corresponding migration might look like this:
class CreatePhysicians < ActiveRecord::Migration[7.0]
def change
create_table :physicians do |t|
t.string :name
t.timestamps
end
end
end
class CreatePatients < ActiveRecord::Migration[7.0]
def change
create_table :patients do |t|
t.string :name
t.timestamps
end
end
end
class CreateAppointments < ActiveRecord::Migration[7.0]
def change
create_table :appointments do |t|
t.datetime :appointment_date
t.timestamps
end
end
end
class AddPhysicianRefToAppointment < ActiveRecord::Migration[7.0]
def change
add_reference :appointments, :physician, null: false, foreign_key: true
end
end
class AddPatientRefToAppointment < ActiveRecord::Migration[7.0]
def change
add_reference :appointments, :patient, null: false, foreign_key: true
end
end
For example, if each supplier has one account, and each account is associated with one account history, then the supplier model could look like this:
class Supplier < ApplicationRecord
has_one :account
has_one :account_history, through: :account
end
class Account < ApplicationRecord
belongs_to :supplier
has_one :account_history
end
class AccountHistory < ApplicationRecord
belongs_to :account
end
The corresponding migration might look like this:
class CreateSuppliers < ActiveRecord::Migration[7.0]
def change
create_table :suppliers do |t|
t.string :name
t.timestamps
end
end
end
class CreateAccounts < ActiveRecord::Migration[7.0]
def change
create_table :accounts do |t|
t.string :account_number
t.timestamps
end
end
end
class CreateAccountHistories < ActiveRecord::Migration[7.0]
def change
create_table :account_histories do |t|
t.integer :credit_rating
t.timestamps
end
end
end
class AddAccountRefToAccountHistory < ActiveRecord::Migration[7.0]
def change
add_reference :account_histories, :account, null: false, foreign_key: true
end
end
class AddSupplierRefToAccount < ActiveRecord::Migration[7.0]
def change
add_reference :accounts, :supplier, null: false, foreign_key: true
end
end
has_and_belongs_to_many
association isn't implemented to make the codebase simpler.
NOTE: If it is requested, it can be added with the next versions.
For example, you might have a picture model that belongs to either an employee model or a product model. Here's how this could be declared:
class Picture < ApplicationRecord
belongs_to :imageable, polymorphic: true
end
class Employee < ApplicationRecord
has_many :pictures, as: :imageable
end
class Product < ApplicationRecord
has_many :pictures, as: :imageable
end
The corresponding migration might look like this:
class CreatePictures < ActiveRecord::Migration[7.0]
def change
create_table :pictures do |t|
t.references :imageable, polymorphic: true, null: false
t.timestamps
end
end
end
class CreateEmployees < ActiveRecord::Migration[7.0]
def change
create_table :employees do |t|
t.string :name
t.timestamps
end
end
end
class CreateProducts < ActiveRecord::Migration[7.0]
def change
create_table :products do |t|
t.string :name
t.timestamps
end
end
end
class Employee < ApplicationRecord
belongs_to :subordinate, optional: true, class_name: "Employee"
has_many :managers, class_name: "Employee", foreign_key: "subordinate_id"
end
The corresponding migration might look like this:
class CreateEmployees < ActiveRecord::Migration[7.0]
def change
create_table :employees do |t|
t.timestamps
end
end
end
class AddManagerRefToEmployee < ActiveRecord::Migration[7.0]
def change
add_reference :employees, :manager, null: true, foreign_key: { to_table: :employees }
end
end
Sometimes, you may want to share fields and behavior between different models.
class Vehicle < ApplicationRecord
end
class Car < Vehicle
end
class SportCar < Car
end
The corresponding migration might look like this:
class CreateVehicles < ActiveRecord::Migration[7.0]
def change
create_table :vehicles do |t|
t.string :type
t.string :color
t.decimal :price
t.timestamps
end
end
end
A model using STI can be used as any model.
EAD has 'table's and 'attribute's to define tables and their attributes in a Rails project.
EAD has 'entity's and 'association's to define any association between entities.
class Author < ApplicationRecord
has_many :books
end
class Book < ApplicationRecord
belongs_to :author
end
class CreateAuthors < ActiveRecord::Migration[7.0]
def change
create_table :authors do |t|
t.string :name
t.timestamps
end
end
end
class CreateBooks < ActiveRecord::Migration[7.0]
def change
create_table :books do |t|
t.datetime :published_at
t.timestamps
end
end
end
class AddAuthorRefToBook < ActiveRecord::Migration[7.0]
def change
add_reference :books, :author, null: false, foreign_key: true
end
end
- Model and migration files are generated for different table and entity names;
class Author < ApplicationRecord
has_many :novels, class_name: "Book", foreign_key: "publisher_id"
end
class Book < ApplicationRecord
belongs_to :publisher, class_name: "Author"
end
class CreateAuthors < ActiveRecord::Migration[7.0]
def change
create_table :authors do |t|
t.string :name
t.timestamps
end
end
end
class CreateBooks < ActiveRecord::Migration[7.0]
def change
create_table :books do |t|
t.date :published_at
t.timestamps
end
end
end
class AddPublisherRefToBook < ActiveRecord::Migration[7.0]
def change
add_reference :books, :publisher, null: false, foreign_key: { to_table: :authors }
end
end
Please check the examples if you need more clarification.
The related buttons should be clicked.
STI can be used by selecting a dropdown next to a table name.
An entity can be added by dragging and dropping a table.
When the table name of an entity is clicked by the right mouse button, a dropdown list will be opened. The related table can be changed by selecting any of the table names.
-
All necessary buttons will be shown when the mouse hover on an entity.
-
'has_one' association can be added by dragging
handler and dropping on one of the gray areas.
Firstly, one association should be selected and then 'Delete' key should be pressed or a button, shown when the association is selected, should be clicked.
Firstly, one entity should be selected and then 'Delete' key should be pressed.
- If there is a through association bidirectionally between two entities referring to the same table, entities used to define 'through' association should be separate.
- If not, only one entity to define 'through' association is enough.