ActiveSupport Outside of Rails
ActiveSupport is the Ruby gem that powers Ruby on Rails. But you don’t need Rails to use it. Many of its utilities are plain Ruby extensions that work perfectly in scripts, gems, and any Ruby project.
This guide covers how to bring ActiveSupport into a non-Rails Ruby project and the most useful parts of it.
What is ActiveSupport?
ActiveSupport is a collection of utility classes and standard library extensions. Rails ships it as a dependency, but it is a fully standalone gem. You can add it to any Ruby project via Bundler:
# Gemfile
gem "activesupport"
Then bundle install and you’re ready to go.
Requiring Only What You Need
One of the best things about ActiveSupport is that you can cherry-pick the parts you want. You do not have to load everything at once.
Load All Core Extensions
The most common approach is to load the core extensions in one line:
require "active_support/core_ext"
This gives you extensions to Ruby’s built-in classes: String, Array, Hash, Object, Numeric, Date, Time, and more.
Load Specific Extensions
If you know exactly what you need, require it directly for faster startup:
require "active_support/core_ext/object/blank"
require "active_support/core_ext/string/inflections"
require "active_support/core_ext/array/wrap"
Here are the most commonly used extension modules:
| Module | Adds |
|---|---|
active_support/core_ext/object | #try, #blank?, #present?, #presence |
active_support/core_ext/string | #blank?, #squish, #titleize, #camelize, #underscore |
active_support/core_ext/array | #wrap, #inquiry, #to_sentence |
active_support/core_ext/hash | #slice, #deep_merge, #.stringify_keys |
active_support/core_ext/numeric | Time and byte size helpers (#days, #megabytes) |
active_support/core_ext/time | Time.current, #ago, #since, #advance |
active_support/core_ext/date | Date.yesterday, Date.tomorrow, #ago, #since |
Core Class Extensions
These are the extensions you will reach for most often in everyday Ruby code.
Object#try
#try calls a method on an object only if it is not nil. It saves you from repetitive nil checks:
require "active_support/core_ext/object/try"
user = nil
user.name # => NoMethodError: undefined method `name' for nil:NilClass
user.try(:name) # => nil
user = OpenStruct.new(name: "Alice")
user.try(:name) # => "Alice"
This is especially useful when working with nested data structures or objects that may or may not be present.
Object#blank? and #present?
These two methods cover all the “empty” cases in one shot:
require "active_support/core_ext/object/blank"
nil.blank? # => true
false.blank? # => true
"".blank? # => true
" ".blank? # => true (whitespace-only strings are blank)
[].blank? # => true
{}.blank? # => true
# present? is just the opposite of blank?
"hello".present? # => true
Ruby already has #empty? on String, Array, and Hash. But #blank? goes further — it handles nil, false, and whitespace-only strings too. No more writing str && !str.empty? && !str.strip.empty?.
String#squish
Removes leading/trailing whitespace and collapses internal whitespace:
require "active_support/core_ext/string"
" hello world ".squish # => "hello world"
There is also #squish! which modifies the string in place.
String#titleize
Converts a string to title case:
require "active_support/core_ext/string/inflections"
"hello world".titleize # => "Hello World"
"active_support".titleize # => "Active Support"
Array#wrap
Array#wrap ensures you always get an array, without the || [] dance:
require "active_support/core_ext/array/wrap"
Array.wrap(nil) # => []
Array.wrap([1, 2]) # => [1, 2]
Array.wrap(42) # => [42]
Compare that to the common pattern [*value] which has surprising behaviour with hashes and OpenStructs:
[*nil] # => [nil] — not an empty array!
[*[1, 2]] # => [1, 2] — works
[*42] # => [42] — works for primitives
Array.wrap is predictable: it always returns an array or an empty array.
Hash#slice
Extract only the keys you want from a hash:
require "active_support/core_ext/hash"
params = { name: "Alice", age: 30, email: "alice@example.com", active: true }
params.slice(:name, :email) # => { name: "Alice", email: "alice@example.com" }
This is extremely useful for whitelisting parameters before passing them somewhere:
def create_user(params)
User.create(params.slice(:name, :email, :password))
end
Hash#deep_merge
Merges two hashes recursively, so nested hashes are merged rather than replaced:
require "active_support/core_ext/hash/deep_merge"
defaults = { db: { host: "localhost", port: 5432 }, pool: 5 }
override = { db: { host: "production.db.com" }, pool: 10 }
defaults.deep_merge(override)
# => { db: { host: "production.db.com", port: 5432 }, pool: 10 }
Plain Ruby #merge would replace the entire :db hash. #deep_merge preserves the keys you do not override.
Time and Date Extensions
ActiveSupport extends Ruby’s time classes with a more readable API.
Time.current
Time.current is like Time.now but timezone-aware. It uses Time.zone if set, otherwise falls back to Time.now:
require "active_support/core_ext/time"
require "active_support/time"
Time.zone = "London"
Time.current # => Tue, 31 Mar 2026 16:00:00 GMT +01:00
In a plain Ruby script, set the timezone before using it:
require "active_support/all"
Time.zone = "America/New_York"
Time.current # => Tue, 31 Mar 2026 11:00:00 EST -05:00
Duration Methods on Time and Date
ActiveSupport adds duration methods (#ago, #from_now, #since, #until) to Time, Date, and DateTime:
require "active_support/core_ext/date"
require "active_support/core_ext/time"
Time.current.ago(1.week) # => roughly 7 days ago
Time.current.from_now(2.hours) # => roughly 2 hours from now
Date.current.yesterday # => the day before today
Date.current.tomorrow # => the day after today
Date Calculations
require "active_support/core_ext/date/calculations"
Date.current - 3.days # => 3 days before today
Date.current + 1.month # => 1 month from today
Date.current.beginning_of_week # => Monday of this week
Date.current.end_of_month # => Last day of this month
Duration Methods on Numeric
These extensions on Numeric make time expressions read naturally:
require "active_support/core_ext/numeric/time"
10.seconds # => 10 seconds
5.minutes # => 5 minutes
2.hours # => 2 hours
1.day # => 1 day
3.weeks # => 3 weeks
6.months # => 6 months
1.year # => 1 year
Chaining them works as expected:
2.hours.ago # => 2 hours ago
1.day.from_now # => tomorrow at the same time
45.minutes.since # => 45 minutes from now
Number Extensions
ActiveSupport adds meaningful units to numbers, which is particularly useful for file sizes and percentages.
Byte Size Helpers
require "active_support/core_ext/numeric/bytes"
1.kilobyte # => 1024
5.megabytes # => 5242880
2.gigabytes # => 2147483648
Percentage Helpers
require "active_support/core_ext/numeric/percentage"
100.percent # => 1.0
50.percent # => 0.5
5.percent.of(200) # => 10.0
These are especially nice in configuration files and calculations:
MAX_MEMORY = 512.megabytes
CACHE_SIZE = 25.percent.of(MAX_MEMORY) # => 134217728 bytes
Tagged Logging
Rails uses ActiveSupport::TaggedLogging to add contextual tags to log output. You can use this in any Ruby project:
require "active_support/tagged_logging"
logger = ActiveSupport::TaggedLogging.new(Rails.logger || Logger.new(STDOUT))
logger.tagged("Request#123") do
logger.info "Processing..."
logger.tagged("User#Alice") do
logger.info "Signed in"
end
end
Output:
[Request#123] Processing...
[Request#123] [User#Alice] Signed in
In a plain Ruby script without Rails, you can wrap any logger:
require "active_support/tagged_logging"
require "logger"
log = Logger.new(STDOUT)
tagged = ActiveSupport::TaggedLogging.new(log)
tagged.tagged("MY_APP", "worker-1") do
tagged.info "Starting job"
tagged.warn "Retrying..."
tagged.error "Job failed"
end
Using ActiveSupport::Dependencies Without Rails
Rails uses ActiveSupport::Dependencies for automatic constant loading. You can use this pattern in plain Ruby to get lazy-loading of constants:
require "active_support/dependencies"
module MyLib
extend ActiveSupport::Dependencies
def self.root
@root ||= Pathname.new(File.dirname(__FILE__))
end
def self.load(file)
require_dependency root.join(file).expand_path
end
end
This keeps constants from being loaded until they are actually referenced. For most projects, standard require is fine, but if you are building something with many optional components, this can speed up startup time significantly.
Performance Considerations
ActiveSupport is modular for a reason. Here is how to keep things fast:
Load only what you use. Loading the full active_support/core_ext adds roughly 0.1–0.3 seconds of startup time. For scripts and CLIs, that is often fine. For library code loaded on every request, load only the specific extensions you need.
Watch the order of requires. Some extensions depend on others. For example, active_support/core_ext/time requires active_support/core_ext/object/try. If you try to load them out of order, you may get NoMethodError. The safe pattern is to load active_support/core_ext for the full suite, or read the dependency tree in the source before cherry-picking.
Be cautious with require "active_support/all" in production. It loads everything — including ActiveSupport::Dependencies autoloading machinery, internationalisation, and ERB::Util. In a non-Rails context, those add overhead for no benefit.
See Also
- /guides/ruby-working-with-strings/ — Learn more string manipulation techniques in pure Ruby
- /guides/ruby-date-and-time/ — Master Ruby’s built-in Time and Date classes
- /guides/ruby-working-with-hashes/ — Common hash patterns and utilities