In this post, we’ll explore some of the most useful core extensions in Rails that enhance how developers work with modules: delegate, concern, and the deprecated but still important alias_method_chain. These tools simplify method delegation, modularize code, and modify method behavior. While alias_method_chain is no longer in use, understanding its history is helpful for maintaining legacy code. We’ll break down how each of these methods works and why they’re valuable, especially when writing cleaner, more efficient Rails applications.
1. Module#delegate
One of the most widely used extensions in Rails is Module#delegate. This method allows you to delegate method calls from one object to another, which is useful when you’re designing classes that need to delegate certain responsibilities to their internal objects.
The delegate method simplifies the delegation process, which otherwise would require manually defining methods that call another object’s methods.
Here’s how delegate works:
Without delegate:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Invoice
def initialize(customer)
@customer = customer
end
def customer_name
@customer.name
end
def customer_address
@customer.address
end
end
With delegate:
1
2
3
4
5
6
7
8
9
class Invoice
attr_reader :customer
delegate :name, :address, to: :customer
def initialize(customer)
@customer = customer
end
end
In the second example, instead of manually writing methods to delegate name and address to the customer object, the delegate method does it for you. This keeps your code DRY (Don’t Repeat Yourself) and more readable.
Why use delegate?
- Reduces boilerplate code.
- Keeps your classes clean by offloading certain method calls to other objects.
- Improves code readability by making clear what methods are being delegated.
2. Module#concern
Another powerful extension provided by ActiveSupport is Module#concern. This helps when organizing and modularizing code through mixins. While Ruby modules can be used to share behavior across classes, concern provides a better structure and solves common issues related to dependencies or initialization sequences in modules.
With concern, you can easily split related methods, validations, or callbacks into separate, reusable modules that can be included in multiple classes.
Example without concern:
1
2
3
4
5
6
7
8
9
10
11
12
13
module Trackable
def track_changes
puts "Tracking changes..."
end
included do
after_save :track_changes
end
end
class Order < ApplicationRecord
include Trackable
end
This works, but it can become messy when you need to manage more callbacks, validations, or dependency methods. You may run into issues with load order or dependencies.
With concern:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module Trackable
extend ActiveSupport::Concern
included do
after_save :track_changes
end
def track_changes
puts "Tracking changes..."
end
end
class Order < ApplicationRecord
include Trackable
end
The ActiveSupport::Concern module ensures that your included block is executed at the correct time, preventing problems with module inclusion order. It also helps by offering a consistent structure for defining reusable logic that involves both instance methods and class-level logic.
Why use concern?
- It makes organizing and modularizing code easier and cleaner.
- Simplifies working with
includedblocks and dependencies within modules. - Allows you to share behavior in a more structured and reliable way, especially for complex mixins.
3. Module#alias_method_chain (Deprecated, but Important to Know)
Module#alias_method_chain was a widely used method in previous versions of Rails to extend or enhance the behavior of existing methods. Although it has been deprecated in favor of using Module#prepend and super, understanding this method is still useful when maintaining legacy codebases or learning about Rails’ history.
alias_method_chain allowed developers to wrap additional behavior around a method, effectively creating a “before” or “after” chain.
Example of alias_method_chain:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class User
def name
"John Doe"
end
def name_with_prefix
"Mr. " + name_without_prefix
end
alias_method_chain :name, :prefix
end
user = User.new
puts user.name # Output: "Mr. John Doe"
Here, alias_method_chain wraps the name method with extra logic (a prefix). The original method name is aliased to name_without_prefix, and the enhanced version name_with_prefix is added in its place.
Post-Rails 5 Alternative:
Since alias_method_chain has been deprecated, Rails now encourages using Module#prepend and super to achieve similar behavior.
Using prepend:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class User
def name
"John Doe"
end
end
module NamePrefixer
def name
"Mr. " + super
end
end
User.prepend NamePrefixer
user = User.new
puts user.name # Output: "Mr. John Doe"
By using prepend, the NamePrefixer module is added to the inheritance chain before the original User class, allowing us to call super to invoke the original name method.
Why avoid alias_method_chain today?
alias_method_chainhas been deprecated becauseprependis more flexible and aligns better with Ruby’s object model.prependprovides a cleaner, more idiomatic way to modify method behavior.
Conclusion
Rails’ ActiveSupport core extensions to Module provide developers with powerful tools to streamline and improve their code.
delegatehelps simplify delegation and reduces boilerplate, making code more maintainable.concernprovides a structured way to create reusable, modular code, improving organization and reducing duplication.alias_method_chain, while deprecated, introduced important concepts around method chaining, now replaced withprependfor a more modern approach.