# Simple mixin
module Loggable
def log(message)
puts "[#{Time.now}] #{self.class.name}: #{message}"
end
end
class User
include Loggable
def save
log("Saving user...")
# Save logic
end
end
user = User.new
user.save # => [2026-02-02 10:30:00] User: Saving user...
# Module with class and instance methods
module Trackable
def self.included(base)
base.extend(ClassMethods)
base.include(InstanceMethods)
end
module ClassMethods
def track_event(event_name)
puts "Tracking class event: #{event_name}"
end
end
module InstanceMethods
def track(event_name)
puts "Tracking instance event: #{event_name} for #{self.class.name}"
end
end
end
class Order
include Trackable
end
Order.track_event('order_created') # Class method
Order.new.track('item_added') # Instance method
# Prepend example (module methods called before class)
module Validator
def save
puts "Validating before save..."
super # Calls original save method
end
end
class Product
prepend Validator
def save
puts "Saving product..."
end
end
Product.new.save
# Validating before save...
# Saving product...
# app/models/concerns/timestampable.rb
module Timestampable
extend ActiveSupport::Concern
included do
# Runs in the context of the including class
before_create :set_created_timestamp
before_update :set_updated_timestamp
end
private
def set_created_timestamp
self.created_at ||= Time.current
end
def set_updated_timestamp
self.updated_at = Time.current
end
end
# app/models/concerns/soft_deletable.rb
module SoftDeletable
extend ActiveSupport::Concern
included do
scope :active, -> { where(deleted_at: nil) }
scope :deleted, -> { where.not(deleted_at: nil) }
default_scope { active }
end
class_methods do
def restore_all
update_all(deleted_at: nil)
end
end
def soft_delete!
update!(deleted_at: Time.current)
end
def restore!
update!(deleted_at: nil)
end
def deleted?
deleted_at.present?
end
end
# app/models/concerns/searchable.rb
module Searchable
extend ActiveSupport::Concern
included do
scope :search, ->(term) {
return all if term.blank?
where(
searchable_columns.map { |col| "#{col} ILIKE :term" }.join(' OR '),
term: "%#{term}%"
)
}
end
class_methods do
def searchable_columns
column_names.select { |col| [:string, :text].include?(columns_hash[col].type) }
end
end
end
# Usage in models
class Post < ApplicationRecord
include SoftDeletable
include Searchable
end
Post.search('ruby')
Post.active
post.soft_delete!
# Concern with dependencies on other concerns
module Publishable
extend ActiveSupport::Concern
included do
include SoftDeletable # Requires SoftDeletable
validates :published_at, presence: true, if: :published?
scope :published, -> { where.not(published_at: nil).active }
scope :draft, -> { where(published_at: nil) }
before_save :set_published_at, if: :publishing?
end
def publish!
update!(published_at: Time.current)
end
def unpublish!
update!(published_at: nil)
end
def published?
published_at.present?
end
private
def publishing?
published_at_changed? && published_at.present?
end
def set_published_at
self.published_at ||= Time.current
end
end
# Concern with configuration
module Sluggable
extend ActiveSupport::Concern
included do
before_validation :generate_slug, on: :create
validates :slug, presence: true, uniqueness: true
end
class_methods do
def slug_from(attribute)
@slug_source = attribute
end
def slug_source
@slug_source || :title
end
end
private
def generate_slug
source = send(self.class.slug_source)
self.slug = source.to_s.parameterize
end
end
# Usage:
class Article < ApplicationRecord
include Sluggable
slug_from :title
end
Ruby modules enable code sharing across classes without inheritance. I use include for instance methods, extend for class methods. prepend inserts module before class in method lookup. Concerns organize shared behavior—validations, scopes, associations. included hook runs when module is included. ClassMethods nested module adds class methods. Modules maintain Single Responsibility and DRY principles. ActiveSupport::Concern simplifies dependencies between concerns. I extract common patterns into modules, making them reusable. Modules compose better than inheritance for shared behavior. Understanding Ruby's method lookup chain—object class, included modules, superclass—enables effective module design. Modules are fundamental to Rails' architecture.