belongs_to | has_one | has_many | has_many :through | has_one :through | has_and_belongs_to_many
Active Record associations declaratively tells Rails that there is a connection between two models.
class Author < ApplicationRecord
has_many :books, dependent: :destroy
end
class Book < ApplicationRecord
belongs_to :author
endUsing associations we can easily
Create a new book for a particular author:
@book = @author.books.create(published_at: Time.now)We can also easily
Delete an author
And delete all of their books:
@author.destroy===
Associations are implemented using macro-style calls, so that you can declaratively add features to your models.
For example, by declaring that one model belongs_to another,
- You instruct Rails to maintain Primary Key and Foreign Key information between instances of the two models,
- You also get a number of utility methods added to your model.
A belongs_to association sets up a one-to-one connection with another model, such that each instance
of the declaring model "belongs to" one instance of the other model.
For example:
- Given that your application includes authors and books
- When each book can be assigned to exactly one author
- Then you'd declare the Book model this way:
class Book < ApplicationRecord
belongs_to :author
end===
If you use the pluralized form: (belongs_to :authors)
class Book < ApplicationRecord
belongs_to :authors
endYou will receive the Error:
Uninitialized constant Book::Authors
This is because Rails automatically infers the class name from the association name.
If the association name is wrongly pluralized, then the inferred class will be wrongly pluralized too.
===
class CreateBooks < ActiveRecord::Migration[5.0]
def change
create_table :authors do |t|
t.string :name
t.timestamps
end
create_table :books do |t|
t.belongs_to :author, index: true
t.datetime :published_at
t.timestamps
end
end
endA has_one association also sets up a one-to-one connection with another model, but with somewhat different semantics (and consequences).
This association indicates that each instance of a model contains or possesses one instance of another model.
For example,
- Given that you have a Supplier model and an Account model
- When each Supplier in your application has only one Account
- Then you would declare the Supplier model like this:
class Supplier < ApplicationRecord
has_one :account
endclass CreateSuppliers < ActiveRecord::Migration[5.0]
def change
create_table :suppliers do |t|
t.string :name
t.timestamps
end
create_table :accounts do |t|
t.belongs_to :supplier, index: true
t.string :account_number
t.timestamps
end
end
endDepending on the use case, you might also need to create a unique index and/or a foreign key constraint on the supplier column for the accounts table.
In this case, the column definition might look like this:
create_table :accounts do |t|
t.belongs_to :supplier, index: true, unique: true, foreign_key: true
# ...
endA has_many association indicates a one-to-many connection with another model.
You'll often find this association on the "other side" of a belongs_to association.
This association indicates that each instance of the model has zero or more instances of another model.
For example:
- Given that you have an application containing Authors and Books
- When the Author has many Books
- Then the Author model could be declared like this:
class Author < ApplicationRecord
has_many :books
endThe corresponding migration might look like this:
class CreateAuthors < ActiveRecord::Migration[5.0]
def change
create_table :authors do |t|
t.string :name
t.timestamps
end
create_table :books do |t|
t.belongs_to :author, index: true
t.datetime :published_at
t.timestamps
end
end
endA has_many :through association is often used to set up a many-to-many connection with another model.
This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding through a third model.
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
endThe corresponding migration might look like this:
class CreateAppointments < ActiveRecord::Migration[5.0]
def change
create_table :physicians do |t|
t.string :name
t.timestamps
end
create_table :patients do |t|
t.string :name
t.timestamps
end
create_table :appointments do |t|
t.belongs_to :physician, index: true
t.belongs_to :patient, index: true
t.datetime :appointment_date
t.timestamps
end
end
endThe collection of join models can be managed via the has_many association methods.
For example:
if you assign:
physician.patients = patients
Then new join models are automatically created for the newly associated objects.
If some that existed previously are now missing,
then their join rows are automatically deleted.
Automatic deletion of join models is direct,
no destroy callbacks are triggered.
The has_many :through association is also useful for
setting up "shortcuts" through nested has_many associations.
For example:
Given: A Document has many Sections
And a Section has many paragraphs
you may sometimes want to get a simple collection of all paragraphs in the document.
You could set that up this way:
class Document < ApplicationRecord
has_many :sections
has_many :paragraphs, through: :sections
end
class Section < ApplicationRecord
belongs_to :document
has_many :paragraphs
end
class Paragraph < ApplicationRecord
belongs_to :section
endWith through: :sections specified, Rails will now understand:
@document.paragraphs
A has_one :through association sets up a one-to-one connection with another model. This association indicates that the declaring model can be matched with one instance of another model by proceeding through a third model. 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
endThe corresponding migration might look like this:
class CreateAccountHistories < ActiveRecord::Migration[5.0]
def change
create_table :suppliers do |t|
t.string :name
t.timestamps
end
create_table :accounts do |t|
t.belongs_to :supplier, index: true
t.string :account_number
t.timestamps
end
create_table :account_histories do |t|
t.belongs_to :account, index: true
t.integer :credit_rating
t.timestamps
end
end
endA has_and_belongs_to_many association creates
a direct many-to-many connection with another model,
with no intervening model.
For example:
Given: that your application includes Assemblies and Parts,
With each Assembly having many Parts
And each Part appearing in many Assemblies
You could declare the models this way:
class Assembly < ApplicationRecord
has_and_belongs_to_many :parts
end
class Part < ApplicationRecord
has_and_belongs_to_many :assemblies
endThe corresponding migration might look like this
class CreateAssembliesAndParts < ActiveRecord::Migration[5.0]
def change
create_table :assemblies do |t|
t.string :name
t.timestamps
end
create_table :parts do |t|
t.string :part_number
t.timestamps
end
create_table :assemblies_parts, id: false do |t|
t.belongs_to :assembly, index: true
t.belongs_to :part, index: true
end
end
end




