ActiveSupport Outside of Rails

· 6 min read · Updated March 31, 2026 · intermediate
ruby activesupport rails stdlib guides

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:

ModuleAdds
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/numericTime and byte size helpers (#days, #megabytes)
active_support/core_ext/timeTime.current, #ago, #since, #advance
active_support/core_ext/dateDate.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