String Inflectors: bring a bit of Rails into JavaScript
The code from this article was taken from the book JavaScript for Rails Developers. Get your copy today! 🧑💻
Ruby developers working with JavaScript often miss the convenience of Ruby’s string manipulation methods. While Ruby (Rails) spoils us with elegant transformations like "user_name".camelize, JavaScript requires you to roll our own helpers or reach for external dependencies.
This article explores creating a lightweight collection of JavaScript string helpers, inspired by Rails’ ActiveSupport inflectors, instead of adding yet another package to your project. Let’s look at how to add these helpers in JavaScript and use them in your Rails app.
From snake_case to camelCase
In Rails, you can easily convert strings with String#camelize. Let’s implement a JavaScript equivalent:
// app/javascript/helpers/stringInflectors.js
export const camelize = (text) => {
return text
.replace(/[-_\s]+(.)?/g, (_, character) => character ? character.toUpperCase() : "")
.replace(/^[A-Z]/, character => character.toLowerCase())
}
This function transforms underscored or hyphenated strings into camelCase format. The first regex replaces any dash, underscore, or space followed by a character with the uppercase version of that character. The second regex ensures the first character is lowercase, giving us proper camelCase.
The
_in(_, character)denotes an unused parameter. This is a common JavaScript convention for parameters that must be included in the function signature but aren’t used in the implementation.
Now how to use it?
// app/javascript/controllers/form_controller.js
import { Controller } from "@hotwired/stimulus"
import { camelize } from "../helpers/stringInflectors"
export default class extends Controller {
connect() {
const propertyName = camelize("user_name") // => "userName"
// Use the camelized property name
this.element.dataset[propertyName] = "value"
}
}
ordinalize: human-friendly numbers
Let’s look at a more specialized helper: ordinalize, which adds the appropriate suffix to numbers (1st, 2nd, 3rd, etc.).
In Rails, this functionality is provided by ActiveSupport::Inflector.ordinalize or the Integer#ordinalize method. The implementation logic in JavaScript is nearly identical:
export const ordinalize = (number) => {
const mod100 = number % 100
if (mod100 >= 11 && mod100 <= 13) return `${number}th`
switch (number % 10) {
case 1: return `${number}st`
case 2: return `${number}nd`
case 3: return `${number}rd`
default: return `${number}th`
}
}
This function handles the special cases for numbers ending in 11, 12 and 13 (which all use th), then applies the appropriate suffix based on the last digit.
Another small aside: The % (modulo) operator returns the remainder after division. Using number % 100 extracts just the last two digits of any number, which is perfect for handling ordinal suffix rules.
For a practical example using this helper in a Stimulus controller:
// app/javascript/controllers/leaderboard_controller.js
import { Controller } from "@hotwired/stimulus"
import { ordinalize } from "../helpers/stringInflectors"
export default class extends Controller {
static targets = ["rank"]
displayRank(position) {
this.rankTarget.textContent = ordinalize(position)
}
}
Product-minded Rails notes
Once a month: straightforward notes on improving UX in Rails—what to simplify, what to measure, and UI/frontend changes that move real usage.
Add even more helpers
This is the complete module, that comes with the Pro package of the book. It includes several other useful transformations:
-
underscore: Converts camelCase to snake_case (Rails:String#underscore) -
dasherize: Converts underscores to dashes (Rails:String#dasherize) -
humanize: Capitalizes first word and converts underscores to spaces (Rails:String#humanize) -
titleize: Capitalizes all words (Rails:String#titleize) -
downcaseandupcase: Simple case converters (Rails:String#downcase,String#upcase) -
parameterize: Makes strings URL-friendly (Rails:String#parameterize)
// app/javascript/helpers/stringInflectors.js
export const camelize = (text) => {
return text
.replace(/[-_\s]+(.)?/g, (_, character) => character ? character.toUpperCase() : "")
.replace(/^[A-Z]/, character => character.toLowerCase())
}
export const underscore = (text) => {
return text
.replace(/([A-Z])/g, "_$1")
.replace(/[-\s]+/g, "_")
.toLowerCase()
.replace(/^_/, "")
}
export const dasherize = (text) => {
return text
.replace(/([A-Z])/g, "-$1")
.replace(/[_\s]+/g, "-")
.toLowerCase()
.replace(/^-/, "")
}
export const humanize = (text) => {
return underscore(text)
.replace(/_id$/, "")
.replace(/_/g, " ")
.replace(/^[a-z]/, character => character.toUpperCase())
}
export const titleize = (text) => {
return humanize(text).replace(/\b[a-z]/g, character => character.toUpperCase())
}
export const downcase = (text) => text.toLowerCase()
export const upcase = (text) => text.toUpperCase()
export const parameterize = (text) => {
return text
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-|-$/g, "")
}
export const ordinalize = (number) => {
const mod100 = number % 100
if (mod100 >= 11 && mod100 <= 13) return `${number}th`
switch (number % 10) {
case 1: return `${number}st`
case 2: return `${number}nd`
case 3: return `${number}rd`
default: return `${number}th`
}
}
export default {
camelize,
underscore,
dasherize,
humanize,
titleize,
downcase,
upcase,
parameterize,
ordinalize
}
To use these helpers in your Rails application, you can import specific helpers:
import { camelize, ordinalize } from "../helpers/stringInflectors"
// Usage: camelize("user_name")
Or import everything as a namespace:
import * as inflector from "../helpers/stringInflectors"
// Usage: inflector.camelize("user_name")
If you’re using importmap-rails, add this to your config/importmap.rb:
pin_all_from "app/javascript/helpers", under: "helpers"
Interested in writing and understanding code like this yourself? I recently wrote the book JavaScript for Rails Developers. It is already read by hundreds of (Rails) developers like you. 😊 This code snippet was included with it along with many other practical, code examples and a practical step by step explanation of writing beautiful, modern JavaScript code.
Want to read me more?
-
Sanitize your strings in JavaScript like a Rails developer
Bring a little Rails into your JavaScript with super useful `sanitize` method to strip unwanting characters from your content. -
Lesser Known Rails Helpers to Write Cleaner View Code
Rails (ActiveSupport/ActionView) has a wide-range of some great helpers to help you (hah!) write cleaner and more readable code. This articles lists the more obscure ones. -
Smarter Use of Stimulus' Action Parameters
Explore a way to remove duplicate methods out of your Stimulus controller and add configuration logic into your HTML instead.
Over to you…
What did you like about this article? Learned something knew? Found something is missing or even broken? 🫣 Let me (and others) know!
Comments are powered by Chirp Form
{{comment}}