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 ApplicationController and ApplicationJob
  • 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:

  1. Create ApplicationRecord:
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end
  1. 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

  1. Keep it minimal: Only add truly shared behavior
  2. Use concerns: Extract complex shared logic to concerns
  3. Document changes: Comment why behavior is shared
  4. 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.

What happened to ActiveRecord::Base in Rails 5? - Abhay Nikam