Introduction
Associations connect your models together, representing relationships between database tables. The one-to-many relationship is the most common pattern in web applications, and Rails makes it remarkably easy to set up.
Key Concepts
has_many: Declares that a model has zero or more instances of another model (e.g., an article has many comments).belongs_to: Declares that a model references another model via a foreign key (e.g., a comment belongs to an article).- Foreign key: The column (e.g.,
article_id) on thebelongs_toside that stores the reference to the parent record. dependent: :destroy: An option that automatically deletes associated records when the parent is deleted.
Real World Context
Almost every database has one-to-many relationships: users have many posts, orders have many items, categories have many products. Understanding associations is essential for modeling any real-world domain in Rails.
Deep Dive
Setting Up the Models
rubyclass Article < ApplicationRecord has_many :comments, dependent: :destroy end class Comment < ApplicationRecord belongs_to :article end
The Migration
rubyclass CreateComments < ActiveRecord::Migration[8.1] def change create_table :comments do |t| t.text :body t.references :article, null: false, foreign_key: true t.timestamps end end end
t.references :article creates an article_id column, an index, and a foreign key constraint.
Using Associations
rubyarticle = Article.create(title: "Rails Associations") comment = article.comments.create(body: "Great article!") article.comments # All comments for this article comment.article # The article this comment belongs to article.comments.count # Number of comments article.comments.build(body: "Draft") # Build without saving
Association Methods
has_many :comments generates:
rubyarticle.comments # Collection article.comments << comment # Add to collection article.comments.delete(comment) # Remove article.comments.destroy_all # Delete all article.comments.find(id) # Find specific article.comments.where(...) # Query article.comments.build(...) # Build new article.comments.create(...) # Create new
Dependent Option
rubyhas_many :comments, dependent: :destroy # Delete with callbacks has_many :comments, dependent: :delete_all # Delete without callbacks has_many :comments, dependent: :nullify # Set FK to NULL has_many :comments, dependent: :restrict_with_error # Prevent deletion
Optional Associations
rubyclass Comment < ApplicationRecord belongs_to :article, optional: true # article_id can be NULL end
Common Pitfalls
- Forgetting the foreign key migration: The
belongs_toside needs a foreign key column. Always uset.referencesin migrations. - Not setting
dependent: Without it, deleting a parent leaves orphaned child records in the database. - Confusing which side gets
belongs_to: The model with the foreign key column always usesbelongs_to.
Best Practices
- Always set
dependent:onhas_manyassociations to prevent orphaned records. - Use
t.referenceswithforeign_key: trueto enforce referential integrity at the database level. - Use
null: falseon foreign key columns when the relationship is required.
Summary
has_manyandbelongs_toset up one-to-many relationships between models.- The
belongs_toside holds the foreign key column (e.g.,article_id). t.references :article, foreign_key: truecreates the column, index, and constraint.- Use
dependent: :destroyto automatically clean up child records. - Rails generates many helpful methods on both sides of the association.
Code Examples
ruby
class Article < ApplicationRecord
has_many :comments, dependent: :destroy
end
class Comment < ApplicationRecord
belongs_to :article
end
# Usage
article = Article.create(title: "Rails")
article.comments.create(body: "Great!")
article.comments.count # => 1