Ruby on Rails Models Deep — Advanced Model Patterns
In this tutorial, you will learn about Ruby on Rails Models Deep. We cover key concepts, practical examples, and best practices to help you master this topic.
Rails models encapsulate business logic with callbacks, validations, scopes, enums, associations, Serialization, and model concerns for reusable behavior sharing.
What You'll Learn
By the end of this tutorial, you'll implement advanced model patterns: callbacks with conditional logic, enums, delegation, STI, model concerns, and custom validators.
Why Model Patterns Matter
Rails models are the heart of the application. Well-structured models with concerns, callbacks, and scopes keep business logic organized and testable.
Real-World Use
A content management system uses STI for content types (Article, Video, Podcast), model concerns for publishable and reviewable behavior, and scopes for content filtering.
Models Path
flowchart LR
A[Rails MVC] --> B[Models Deep]
B --> C[Callbacks]
B --> D[Enums]
B --> E[STI]
B --> F[Concerns]
B --> G{You Are Here}
style G fill:#f90,color:#fff
Callbacks with Conditions
Apply callbacks conditionally.
class Order < ApplicationRecord
before_save :calculate_total, if: :items_changed?
before_save :set_status, on: :create
after_save :send_confirmation, unless: :test_order?
around_save :log_changes
private
def items_changed?
saved_change_to_order_items? || new_record?
end
def test_order?
email&.include?("@example.com")
end
end
Enums
Enums map integer columns to named values.
class Order < ApplicationRecord
enum :status, {
pending: 0,
confirmed: 1,
processing: 2,
shipped: 3,
delivered: 4,
cancelled: 5,
}, default: :pending, validate: true
enum :payment_status, {
unpaid: 0,
paid: 1,
refunded: 2,
chargeback: 3,
}
scope :active, -> { where.not(status: :cancelled) }
scope :needs_attention, -> { where(status: [:pending, :processing]) }
end
# Usage
order.pending? # true/false
order.confirmed! # Update to confirmed
Order.confirmed # Where clause scope
Delegation
Delegate methods to associated objects.
class User < ApplicationRecord
has_one :profile, dependent: :destroy
delegate :bio, :website, :location, to: :profile, prefix: true
delegate :avatar_url, to: :profile, allow_nil: true
delegate :name, to: :profile, prefix: :user, allow_nil: true
end
class Profile < ApplicationRecord
belongs_to :user
end
# Usage
user.profile_bio # user.profile.bio
user.profile_avatar_url # user.profile&.avatar_url
user.user_name # user.profile&.name
Single Table Inheritance
Share a table across related models.
class Content < ApplicationRecord
self.inheritance_column = :type
scope :published, -> { where(published: true) }
def display_type
type.demodulize
end
end
class Article < Content
validates :body, presence: true
end
class Video < Content
validates :video_url, presence: true
end
class Podcast < Content
validates :audio_url, presence: true
end
Common Mistakes
1. Callback Chain Overload
Too many callbacks on a single model make saving unpredictable. Use service objects.
2. Using Enum Integer Values Directly
Always reference enum values by name. Hardcoded integers break when the enum changes.
3. STI Without Discriminator Column
STI requires a type column. Rails defaults to the class name.
4. Delegation Without allow_nil
Delegating to a nil association raises NoMethodError. Use allow_nil: true.
5. Callbacks That Query the Database
Callbacks should be fast. Slow callbacks delay saves and cause timeouts.
Practice Questions
1. What callback runs before creating a new record?
before_create.
2. How do you define an enum in Rails 7+?
enum :status, { pending: 0, active: 1 }, default: :pending.
3. What is delegation in Rails?
Delegating method calls from one class to an associated object.
4. What is STI?
Single Table Inheritance - multiple models share a single database table with a type column.
5. Challenge: Create a model with callbacks, enums, and delegation.
class Subscription < ApplicationRecord
belongs_to :user
delegate :email, :name, to: :user, prefix: true, allow_nil: true
enum :status, { trial: 0, active: 1, paused: 2, cancelled: 3 }
before_create :set_trial_end
after_save :notify_user, if: :saved_change_to_status?
private
def set_trial_end
self.trial_ends_at = 14.days.from_now
end
def notify_user
SubscriptionMailer.status_change(self).deliver_later
end
end
FAQ
Mini Project: Content Management with STI
Build a content management system using STI.
class Content < ApplicationRecord
belongs_to :author, class_name: "User"
validates :title, presence: true
scope :published, -> { where(published: true) }
end
class Article < Content
validates :body, presence: true
end
class Video < Content
validates :video_url, presence: true
end
class Podcast < Content
validates :audio_url, presence: true
end
What's Next
Rails ActiveRecord Deep Rails Validations Deep Rails Associations Deep
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro