What happened to ActiveRecord::Base in Rails 5?
Rails 5 introduced a significant change: ActiveRecord models no longer directly inherit from ActiveRecord::Base. Instead, they inherit from ApplicationRecord, which itself inherits from ActiveRecord::Base. This change provides a single point of configuration for all models.
Before Rails 5
Previously, all models directly inherited from ActiveRecord::Base:
# Rails 4 and earlier
class User < ActiveRecord::Base
end
class Post < ActiveRecord::Base
end
Rails 5 Change
Rails 5 introduced ApplicationRecord:
# app/models/application_record.rb (auto-generated)
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
# Your models now inherit from ApplicationRecord
class User < ApplicationRecord
end
class Post < ApplicationRecord
end
Why the Change?
This change provides several benefits:
- Single configuration point: Configure all models in one place
- Consistency: Same pattern as
ApplicationControllerandApplicationJob - Flexibility: Easy to add shared behavior to all models
- Organization: Clear separation of application-specific code
ApplicationRecord
Auto-Generated File
When you create a new Rails 5 app, ApplicationRecord is automatically created:
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
Adding Shared Behavior
Add shared behavior to all models:
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
# Shared scopes
scope :recent, -> { order(created_at: :desc) }
scope :active, -> { where(active: true) }
# Shared methods
def self.search(query)
where("name ILIKE ?", "%#{query}%")
end
# Shared callbacks
before_save :normalize_data
private
def normalize_data
# Normalization logic
end
end
Migration from Rails 4
Automatic Migration
When upgrading to Rails 5, Rails generators create ApplicationRecord:
rails app:update
Manual Migration
If upgrading manually:
- Create
ApplicationRecord:
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
- Update existing models:
# Before
class User < ActiveRecord::Base
end
# After
class User < ApplicationRecord
end
Real-World Examples
Shared Configuration
Configure all models in one place:
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
# Set default timezone
self.time_zone_aware_attributes = true
# Enable query caching
self.query_cache = true
end
Shared Scopes
Define scopes available to all models:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
scope :created_today, -> { where(created_at: Date.current.all_day) }
scope :created_this_week, -> { where(created_at: 1.week.ago..) }
scope :created_this_month, -> { where(created_at: 1.month.ago..) }
end
Shared Validations
Add validations to all models:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
validates :created_at, presence: true
validates :updated_at, presence: true
end
Benefits
Consistency
Follows the same pattern as other Rails abstractions:
# Controllers
class ApplicationController < ActionController::Base
end
# Jobs
class ApplicationJob < ActiveJob::Base
end
# Models
class ApplicationRecord < ActiveRecord::Base
end
Configuration
Single place to configure all models:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
# Global model configuration
connects_to database: { writing: :primary, reading: :replica }
# Shared concerns
include Timestampable
include Sluggable
end
Common Patterns
Including Concerns
Share concerns across all models:
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
include Timestampable
include SoftDeletable
include Searchable
end
Default Scopes
Set default scopes:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
default_scope { where(deleted_at: nil) }
end
Global Callbacks
Add callbacks to all models:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
before_save :set_updated_at
after_create :log_creation
private
def set_updated_at
self.updated_at = Time.current
end
def log_creation
Rails.logger.info("Created #{self.class.name}: #{id}")
end
end
Best Practices
- Keep it minimal: Only add truly shared behavior
- Use concerns: Extract complex shared logic to concerns
- Document changes: Comment why behavior is shared
- Test shared behavior: Ensure shared code works for all models
What Still Works
Models still work the same way:
class User < ApplicationRecord
# All ActiveRecord features still work
validates :email, presence: true
has_many :posts
scope :active, -> { where(active: true) }
end
Conclusion
Rails 5's introduction of ApplicationRecord provides a consistent pattern for configuring all models in one place, similar to ApplicationController and ApplicationJob. This change makes it easier to add shared behavior, configure models globally, and maintain consistency across your application. While models no longer directly inherit from ActiveRecord::Base, all ActiveRecord functionality remains available through ApplicationRecord.