Module mixins and concerns for code reuse

Sarah Mitchell Feb 2026
3 tabs
# 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...
3 files · ruby Explain with highlit

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.