Skip to content

Ror Associations

DodaTech 4 min read

title: Ruby on Rails Associations — Complete Guide to Model Relationships description: 'Learn Ruby on Rails associations: belongs_to, has_many, has_one, has_many :through, polymorphic associations, dependent options, and eager loading.' date: 2026-06-28 lastmod: 2026-06-28 weight: 21 tags: [backend, ror]


Rails associations define relationships between models using a declarative DSL, enabling intuitive navigation from one record to related records through foreign keys and join tables.

## What You'll Learn

By the end of this tutorial, you'll implement belongs_to, has_many, has_one, has_many :through, polymorphic associations, configure dependent actions, and avoid N+1 queries.

## Real-World Use

An e-commerce app has User has_many Orders, Order belongs_to User, Order has_many Products through OrderItems, and Product has_many Orders through OrderItems.

## Associations Learning Path

```mermaid
flowchart LR
  A[Validations] --> B[Associations]
  B --> C[Forms]
  C --> D[Authentication]
  D --> E[Authorization]
  B --> F{You Are Here}
  style F fill:#f90,color:#fff

Basic Associations

# One-to-Many
class User < ApplicationRecord
  has_many :posts, dependent: :destroy
  has_many :comments, dependent: :destroy
end

class Post < ApplicationRecord
  belongs_to :user
  has_many :comments, dependent: :destroy
end

class Comment < ApplicationRecord
  belongs_to :post
  belongs_to :user
end

has_many :through

# Many-to-Many through join table
class Physician < ApplicationRecord
  has_many :appointments, dependent: :destroy
  has_many :patients, through: :appointments
end

class Patient < ApplicationRecord
  has_many :appointments, dependent: :destroy
  has_many :physicians, through: :appointments
end

class Appointment < ApplicationRecord
  belongs_to :physician
  belongs_to :patient
  validates :appointment_date, presence: true
end

has_and_belongs_to_many

# Direct many-to-many (no join model)
class Product < ApplicationRecord
  has_and_belongs_to_many :categories
end

class Category < ApplicationRecord
  has_and_belongs_to_many :products
end
# Requires join table: create_join_table :products, :categories

Polymorphic Associations

class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
  belongs_to :user
end

class Post < ApplicationRecord
  has_many :comments, as: :commentable, dependent: :destroy
end

class Photo < ApplicationRecord
  has_many :comments, as: :commentable, dependent: :destroy
end
# Comments table needs: commentable_type (Post/Photo) and commentable_id

Association Options

class User < ApplicationRecord
  has_many :posts, -> { order(created_at: :desc) },   # Default scope
           foreign_key: :author_id,                     # Custom FK
           primary_key: :uuid,                          # Custom PK
           dependent: :destroy,                         # Cascade delete
           inverse_of: :author,                         # Bidirectional
           counter_cache: true                          # Cache count
end

class Post < ApplicationRecord
  belongs_to :author, class_name: "User",              # Custom class
             foreign_key: :author_id,
             touch: true,                               # Touch parent on save
             optional: true                             # Allow nil FK
end

Common Mistakes

1. Missing dependent: :destroy

Without dependent, deleting a user leaves orphaned posts. Always specify cascade behavior.

2. Wrong Foreign Key

Rails assumes foreign_key is model_id (user_id). Customize with class_name and foreign_key for non-standard names.

3. Not Using :through for Complex Relationships

has_and_belongs_to_many is useful but lacks join model features. Use has_many :through for rich join tables.

4. Incorrect Polymorphic Column Types

Ensure commentable_id is integer (not string) and commentable_type is string in the migration.

5. N+1 Queries in Associations

@posts.each { |p| p.user.name } issues N queries. Use includes(:user) for eager loading.

Practice Questions

1. What is the difference between has_many and has_one?

has_many returns a collection (multiple records). has_one returns a single record.

2. When would you use has_many :through?

When you need a join model with additional attributes (quantity, date). For simple joins, use HABTM.

3. What is a polymorphic association?

A model that can belong to multiple other models with a single association. Comment can belong to Post or Photo.

4. What does dependent: :destroy do?

When the parent is destroyed, all associated records are also destroyed. Prevents orphaned records.

5. Challenge: Create associations for a blog with users, posts, comments, and tags.

class User < ApplicationRecord
  has_many :posts, dependent: :destroy
  has_many :comments, dependent: :destroy
end
class Post < ApplicationRecord
  belongs_to :user
  has_many :comments, dependent: :destroy
  has_and_belongs_to_many :tags
end
class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :post
end
class Tag < ApplicationRecord
  has_and_belongs_to_many :posts
end

FAQ

What is the difference between has_many :through and HABTM?

Through uses a full model (appointments). HABTM uses a join table (no model). Use Through for additional attributes.

How do I set up a self-join (user follows user)?

has_many :followings, class_name: 'Follow', foreign_key: :follower_id. has_many :followed_users, through: :followings, source: :followed.

What is inverse_of?

Optimizes memory by setting the inverse association. belongs_to :post, inverse_of: :comments.

How do I validate associated records?

Use accepts_nested_attributes_for :posts with reject_if and allow_destroy options.

What is counter_cache?

Caches the count of associated records in a column (posts_count). Avoids COUNT queries.

Mini Project: Blog Associations

Create complete associations for a blog with Users, Posts, Comments, and Tags.

class User < ApplicationRecord
  has_many :posts, dependent: :destroy
  has_many :comments, dependent: :destroy
end
class Post < ApplicationRecord
  belongs_to :user, counter_cache: true
  has_many :comments, dependent: :destroy
  has_and_belongs_to_many :tags
end
class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :post, counter_cache: true, touch: true
end
class Tag < ApplicationRecord
  has_and_belongs_to_many :posts
end

What's Next

Ruby on Rails Forms Ruby on Rails Authentication

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro