Words and Code

One writer’s journey from words to code.

Inflections Everywhere: Using ActiveSupport Inflector

#technicaltuesdays, rails, ruby


Words are pretty important. But do you know what’s more important than words? Grammar. (Can you tell that I was an English major?) Despite how big of a book nerd I am, there’s acually a crucial reason as to why we should keep things like grammar in consideration: convention.

At it’s very core — pun totally intended — the Rails framework is based in conventions. We rely on the framework to create our models, controllers, and views in a specific file structure, and for them to be named in a certain way. But what we often forget is that we also rely on Rails to be smart enough to handle strange edge cases, like knowing that a mice table should store the Mouse model objects, and that the MiceController should be responsible for passing those objects back and forth!

It all seems pretty automagical. But we have to keep in mind that it was the Rails core team that created and established these conventions, which means that they’re not magic — they’re just code! And as much as we can rely on preexisting Rails conventions, there might be times that we need to tweak our code to abide by those conventions. And because computers are not people (and because English is a crazy language with so many strange exceptions), we’re probably going to run into a roadblock when dealing with grammar naming conventions. Thankfully, there’s a great tool to help with this problem: the Rails Inflector, also known as every grammar nerd’s dream.

Meet The Inflector

The Rails Inflector is actually a part of the ActiveSupport module, which is truly a beast of a module, and probably warrants a few blog posts of its own. The tl;dr version of ActiveSupport is this: it provides a bunch of different patterns to transform simple Ruby strings. The inflector library in particular is responsible for handling the pluralization of different strings.

An important thing to note about the inflections library is that it’s pretty much set in stone. According to the documentation, these rules are never going to change so that Rails can remain backwards-compatible for older applications:

“The Rails core team has stated patches for the inflections library will not be accepted in order to avoid breaking legacy applications which may be relying on errant inflections. If you discover an incorrect inflection and require it for your application or wish to define rules for languages other than English, please correct or add them yourself.”

Basically, what this means is that Rails provides us with some basic inflections; however, if we want to create our own custom grammar rules (or if we notice something that’s incorrect), we have to write our own inflections for our application. It’s also worth noting that if we want to create models that are not English words, we’d need to write our own pluralize rules for those as well. But before we go about writing completely new inflections, let’s first see what inflector methods we have available to us!

Inflector Methods

The ActiveSupport::Inflector module has a handful of public instance methods that are available for us to use. In fact, when I was first learning Rails, I played around with these methods in irb, but didn’t really know (much less understand) where they were coming from. But it turns out that the Inflector methods can be super useful! Here are some of my favorites:

humanize

This method is great for displaying an attribute name to end users. It deletes any leading underscores, replaces underscores with spaces, downcase all words (except acronyms), and capitalizes the first word. Basically, it makes your attributes human-readable, which can be helpful for displaying an error message to your user:

1
2
3
4
 rails console
Loading development environment (Rails 4.1.4)
irb(main):001:0> humanize(author.first_name)
=> "First name"

titleize

The titleize method is pretty perfect for our bookstore application. It capitalizes all the words and replaces underscores with spaces:

1
2
irb(main):002:0> 'of_mice_and_men'.titleize
=> "Of Mice And Men"

Protip: this method is also aliased as titlecase.

parameterize

This method replaces special characters in a string so that it can be used in a URL (think sluggable names with hyphens):

1
2
irb(main):003:0> 'Of Mice And Men'.parameterize
=> "of-mice-and-men"

singularize

The singularize method does exactly what you think it would do: it returns the singular form of a word in a string:

1
2
3
4
irb(main):004:0> 'mice'.singularize
=> "mouse"
irb(main):005:0> 'men'.singularize
=> "man"

pluralize

And the pluralize method does the opposite things: returns the plural form of a word in string format:

1
2
3
4
irb(main):006:0> "mouse".pluralize
=> "mice"
irb(main):007:0> "man".pluralize
=> "men"

There are tons more Inflector methods that are very well-documented. In fact, there are so many great methods that you might be thinking to yourself, why would I ever have to write my own methods?

Well, what if we wanted Specimen objects, which needed to be pluralized as Specimens. We could assume that Rails will handle that for us…or we could double-check:

1
2
irb(main):008:0> "specimen".pluralize
=> "specimen"

Oops! It seems like the predefined inflections are taking hold here and parsing “men” as the plural form of “man”, like we saw earlier. You know what this means…time to write our own inflections!

New Inflection Rules

One of the coolest public instance methods of the `ActiveSupport::Inflector module is the method that allows us to specify our own inflector rules. This method is appropiately named inflections, and it does some interesting things.

The inflections method yields to a singleton instance of ActiveSupport::Inflector::Inflections. It can be passed an optional locale, which is how we could write inflection rules for other languages; the default locale is English (specified as the argument :en).

We can write our own inflections inside of the config/initializers/inflections.rb file. This file actually already exists and will look like this when we first open it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Be sure to restart your server when you modify this file.

# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
#   inflect.plural /^(ox)$/i, '\1en'
#   inflect.singular /^(ox)en/i, '\1'
#   inflect.irregular 'person', 'people'
#   inflect.uncountable %w( fish sheep )
# end

# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
#   inflect.acronym 'RESTful'
# end

We can already see how to go about writing our inflections with the examples in this file, including some of the methods we can use, depending on what our edge case is. There are actually a lot of methods available to us inside of our inflections block, some of the most helpful being plural, singular, uncountable, and irregular. In our case, we’re dealing with an irregular inflection wherein specimen needs to be pluralized as specimens, so we’ll use the irregular method, which takes two arguments: the singular and the plural form of the word as strings.

1
2
3
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.irregular 'specimen', 'specimens'
en

Awesome! Now our entire application will know about this inflection rule. And the really great thing about this is that our new rule that we just wrote is added at the top of this file, which means that our irregular rule for specimen will be the first of the singularization and pluralization rules that is run. This ensures that our rules will always run before any of the preexisting rules that come with ActiveSupport::Inflector.

Whew — that was quite an inflection adventure! But now the next time we have a grammar mistake, we can fix it easily, just like this slightly strange puppet (is a gopher? A beaver? I don’t know!) keeps telling us to do:

tl;dr?

  • The ActiveSupport::Inflector handles a lot of the grammar rules in Rails. The inflections.rb file is where we can write our own inflection rules. Check out all the preexisting inflections in the Rails source code.
  • Curious how Rails knows what grammar rules to follow? Check out this blog post, which explains it all.
  • If you are very brave, dig through the source code for all of the methods available to inflections.