Rails magic is a widespread term among developers working with Ruby on Rails application. Is it an overstatement? Well, it depends. During day-to-day work, there isn’t usually enough time to study deeply Ruby on Rail source code. Even though it is an effective way to develop programming skills and understand the framework in-depth, sooner or later everybody finds mysterious places in a codebase that may cause frustration.
I bet that you have already seen
if Rails.env.production? condition several times. Have you ever thought where it comes from? Today I learned that
ActiveSupport::StringInquirer1 class is a part of Ruby on Rails codebase and adds some magic powers to
String objects 🙂
Wrapping a string in this class gives you a prettier way to test for equality.
In Rails codebase, we can see that the
env method uses the class:
def env @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence || "development") end
Surprisingly, the method does not return
String object, but
 pry(main)> Rails.env => "development"  pry(main)> Rails.env.class => ActiveSupport::StringInquirer
So now it’s time to go even deeper and check the source code of
class StringInquirer < String private def respond_to_missing?(method_name, include_private = false) (method_name[-1] == "?") || super end def method_missing(method_name, *arguments) if method_name[-1] == "?" self == method_name[0..-2] else super end end end
Let’s break its magic down using the
"development", but its class isn’t
String, so all its methods are available (
development?method is not defined in
method_missingone is executed as a fallback.
method_missingchecks if a method name ends with
- In our case it ends with
self == method_name[0..-2]comparison is made.
"development"string is equal to
"development?[0..-2]", so the method returns
When to use
First of all, you need to be brave enough to consciously use Rails magic 😉 Being serious, whenever you do strings comparison the class can be used instead. Please do some benchmarking first, though.
 pry(main)> name = "Johny" => "Johny"  pry(main)> name.Johny? NoMethodError: undefined method `Johny?' for "Johny":String  pry(main)> name.inquiry.Johny? => true  pry(main)> name.inquiry.class => ActiveSupport::StringInquirer  pry(main)> ActiveSupport::StringInquirer.new("Johny").Johny? => true
Whenever you find a fragment of code you do not understand fully, it’s a good idea to go deeper and try to understand it fully. Thanks to such an approach I explored and understood new fragments of Ruby on Rails source code. As a result, Rails is a bit less magical to me 🧙.