Ror Models
title: Ruby on Rails Models — Complete Guide to Data and Business Logic description: 'Learn Ruby on Rails models: Active Record basics, validations, callbacks, scopes, model associations, query interface, and organizing business logic in models.' date: 2026-06-28 lastmod: 2026-06-28 weight: 17 tags: [backend, ror]
Ruby on Rails models use Active Record for object-relational mapping, providing an intuitive interface for database queries, validations, associations, and business logic.
## What You'll Learn
By the end of this tutorial, you'll create models with Active Record, define validations, implement callbacks, write scopes for common queries, configure associations, and keep models organized.
## Real-World Use
A User model has validations (email uniqueness, password length), scopes (active, admin), associations (has_many :posts), and callbacks (hash password before create).
## Models Learning Path
```mermaid
flowchart LR
A[Views] --> B[Models]
B --> C[Active Record]
C --> D[Migrations]
D --> E[Validations]
B --> F{You Are Here}
style F fill:#f90,color:#fff
Model with Validations
class User < ApplicationRecord
# Associations
has_many :posts, dependent: :destroy
has_many :comments, dependent: :destroy
# Validations
validates :email, presence: true, uniqueness: { case_sensitive: false }
validates :username, presence: true, length: { minimum: 3, maximum: 30 }
validates :password, length: { minimum: 8 }, if: :password_required?
# Callbacks
before_save :downcase_email
after_create :send_welcome_email
# Scopes
scope :active, -> { where(active: true) }
scope :recent, -> { order(created_at: :desc) }
scope :admin, -> { where(role: :admin) }
# Custom methods
def display_name
username.presence || email.split("@").first
end
private
def downcase_email
self.email = email.downcase
end
def password_required?
new_record? || password.present?
end
def send_welcome_email
UserMailer.welcome(self).deliver_later
end
end
Query Interface
# Basic queries
Post.find(1) # Find by ID
Post.find_by(title: "Hello") # First match
Post.where(published: true) # Filter
Post.where("created_at > ?", 1.week.ago)
Post.order(created_at: :desc)
Post.limit(10).offset(20)
Post.select(:id, :title)
# Chaining
Post.published.recent.limit(5)
User.active.where("created_at > ?", 30.days.ago)
# Aggregation
Post.count
Post.where(published: true).count
Post.group(:status).count
# Existence
Post.exists?(id: 1)
Post.any?
Post.none?
Callbacks
class Order < ApplicationRecord
before_validation :set_default_status
before_save :calculate_total
after_create :send_confirmation
after_update :notify_status_change, if: :saved_change_to_status?
around_save :measure_performance
private
def set_default_status
self.status ||= :pending
end
def calculate_total
self.total = line_items.sum(&:subtotal)
end
def send_confirmation
OrderMailer.confirmation(self).deliver_later
end
def measure_performance
start = Time.current
yield
Rails.logger.info "Order save took #{Time.current - start}s"
end
end
Scopes
class Post < ApplicationRecord
# Simple scopes
scope :published, -> { where(published: true) }
scope :drafts, -> { where(published: false) }
scope :recent, -> { order(created_at: :desc) }
scope :popular, -> { where("views_count > ?", 100) }
# With parameters
scope :by_author, ->(author_id) { where(user_id: author_id) }
scope :search, ->(term) {
where("title ILIKE :term OR body ILIKE :term", term: "%#{term}%")
}
# Default scope (use with caution)
default_scope { order(created_at: :desc) }
end
Common Mistakes
1. Fat Models
Putting everything in models creates God objects. Extract service objects for complex business logic.
2. Too Many Callbacks
Callbacks that trigger other callbacks create hard-to-debug chains. Keep them simple.
3. Forgetting dependent: :destroy
Without dependent: :destroy, deleting a user leaves orphaned posts. Always specify cascade behavior.
4. N+1 Queries
@posts.each { |p| p.user.name } issues N queries. Use includes(:user) for eager loading.
5. Not Using Scopes
Repeating where clauses everywhere violates DRY. Define scopes in the model.
Practice Questions
1. What is Active Record?
The Rails ORM that maps Ruby classes to database tables, providing query methods, validations, and associations.
2. What is the difference between find and find_by?
find raises RecordNotFound if not found. find_by returns nil. find uses primary key, find_by uses any column.
3. What are scopes?
Named query fragments that can be chained. Scope :recent, -> { order(created_at: :desc) }.
4. What is the N+1 problem?
Executing N queries for N related records instead of 2 queries. Fixed with includes(:association).
5. Challenge: Create a Post model with validations, scopes, associations, and a custom method.
class Post < ApplicationRecord
belongs_to :user
has_many :comments, dependent: :destroy
validates :title, presence: true, length: { minimum: 5 }
validates :body, presence: true
scope :published, -> { where(published: true) }
scope :recent, -> { order(created_at: :desc) }
def excerpt
truncate(body, length: 100)
end
end
FAQ
Mini Project: User and Post Models
Create User and Post models with validations, associations, and scopes.
class User < ApplicationRecord
has_many :posts, dependent: :destroy
validates :email, presence: true, uniqueness: true
has_secure_password
end
class Post < ApplicationRecord
belongs_to :user
validates :title, presence: true
scope :recent, -> { order(created_at: :desc) }
end
What's Next
Ruby on Rails Active Record Ruby on Rails Migrations
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro