Why Metaprogramming is Cool
Every Ruby on Rails developer has likely used Rails.env.production? , Rails.env.development? , or similar calls to check the current environment. But have you ever wondered how ...
Rubycode
05 November 2024 · 2 min read
Every Ruby on Rails developer has likely used Rails.env.production?, Rails.env.development?, or similar calls to check the current environment. But have you ever wondered how this magic works? In other languages, checking the environment often looks like ENV == 'production', which can quickly become unwieldy with multiple environment checks. So what exactly happens under the hood when you execute Rails.env.production?
When you call Rails.env.production?, you're actually invoking a method named production? on an instance of ActiveSupport::StringInquirer, which is part of Rails' ActiveSupport library. ActiveSupport::StringInquirer is a utility class that enables dynamic environment checking in Rails projects.
But if you look at the ActiveSupport::StringInquirer source, you'll notice something interesting: there is no explicit production? or development? method defined. Instead, StringInquirer uses metaprogramming to respond dynamically to any environment check by leveraging Ruby's method_missing.
How method_missing enables dynamic method handling
Here's the magic of method_missing at work:
class ActiveSupport::StringInquirer < String
private
def method_missing(method_name, *args, &block)
if method_name.to_s.end_with?("?")
# Checks whether the method name matches the environment
self == method_name.to_s.chop
else
# Otherwise fall back to the default, which raises NoMethodError
super
end
end
end
In Ruby, when a method is called on an object and it is not found, Ruby falls back to method_missing. It is defined in BasicObject, the root of Ruby's class hierarchy, and raises a NoMethodError by default. ActiveSupport::StringInquirer overrides it to interpret any call ending in ? as an environment check.
For example, when you call Rails.env.production?, method_missing sees the ? at the end, removes it, and checks whether the environment string (self) matches "production". If Rails.env is "production" it returns true; otherwise it returns false.
Metaprogramming can be confusing at first, but once you get used to it you'll realise it drastically reduces the amount of code needed and keeps it clean and focused on what matters. By handling methods dynamically, metaprogramming gives us the flexibility to write more expressive, adaptable code without redundancy. In the case of Rails.env.production?, it lets Rails offer a powerful, simple way to manage environments with very little code — one of the many reasons Rails is such a joy to work with.
More from the blog
All articles-
Engineering
How to write an implementation plan your team can trust
What every implementation plan for a Rails feature must have, from the decisions only people can make to safe migrations, testable acceptance criteria and a sign-off, and how to make your team follow it every time with questions, settings and guards in code.
06 October 2026 · 11 min read
-
AI Engineering
Where Is the Engineering Work Now? Redesigning Development Around AI
Agents already write most of the code in a sprint, yet we still run it as if every developer types their own ticket. Where the real engineering work is today, and what changes when you redesign the process around AI.
02 October 2026 · 5 min read
-
Gems
The agents write the code. Your team decides what gets built.
plan_driven is an open source Ruby gem that takes a Rails feature from an approved implementation plan to merged, tested pull requests, with one Cursor agent per ticket and guards written in Ruby at every step.
30 September 2026 · 17 min read