Reason #109 •
April 19th, 2026
ActiveSupport: String#underscore and friends
Rails naming conventions are famously opinionated. ActiveSupport's inflector API is a big part of what makes those conventions feel quite effortless to work with, but what I'd like to highlight here is that they're also just generally useful for string format normalization:
Ruby
"TheyNameFunctionsLikeThisInCSharp".underscore
# => "they_name_functions_like_this_in_c_sharp"
"but_in_ruby_they_imply_constants".camelcase
# => "ButInRubyTheyImplyConstants"
"snake_case_is_the_best_case".camelcase(:lower)
# => "snakeCaseIsTheBestCase"
"but_what_about_modern_filenames".dasherize
# => "but-what-about-modern-filenames"
"i_prefer_human_language_myself".humanize
# => "I prefer human language myself"
JavaScript
const underscore = (string) =>
string
.replace(/::/g, "/")
.replace(/([A-Z\d]+)([A-Z][a-z])/g, "$1_$2")
.replace(/([a-z\d])([A-Z])/g, "$1_$2")
.replace(/-/g, "_")
.toLowerCase();
const camelcase = (string, mode = "upper") => {
const out = string
.split("/")
.map(part =>
part
.split("_")
.filter(Boolean)
.map(word => word[0].toUpperCase() + word.slice(1))
.join("")
)
.join("::");
return mode === "lower" ? out[0].toLowerCase() + out.slice(1) : out;
};
const dasherize = (string) => string.replaceAll("_", "-");
const humanize = (string) =>
string
.replace(/_id$/, "")
.replace(/_/g, " ")
.replace(/^\w/, c => c.toUpperCase());
underscore("TheyNameFunctionsLikeThisInCSharp");
// => "they_name_functions_like_this_in_c_sharp"
camelcase("but_in_ruby_they_imply_constants");
// => "ButInRubyTheyImplyConstants"
camelcase("snake_case_is_the_best_case", "lower");
// => "snakeCaseIsTheBestCase"
dasherize("but_what_about_modern_filenames");
// => "but-what-about-modern-filenames"
humanize("i_prefer_human_language_myself");
// => "I prefer human language myself"
History
underscore, camelcase and humanize were available in the very early ActiveSupport releases before Rails 1.0.
dasherize arrived a bit later in Rails 1.1.0, released in 2006. The commit that introduced it was part of the same broader push that brought Hash#to_xml and Array#to_xml into ActiveSupport.