Rails initializers you don't know about - Inflections

Rails come with a lot of initializers that we are not quite familiar with. One of them is the inflections initializer. In this post, we will look at what inflections.rb is and how we can use them.

What are Inflections?

Inflector is a part of the ActiveSupport library that provides methods to pluralize and singularize words in a given string. Inflections are rules that specify how words should be pluralized or singularized in a given context. These rules are defined in a file called “inflections.rb”.

This is what we would get in a new Rails 7 inflection file.

# config/initializers/inflections.rb
# 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

This file is commented out by default because the inflections are already defined in the Rails source code. Also, any new patch to these rules will not be accepted in the library to avoid breaking existing applications. If we need to provide extra rules, we can do so in the inflections.rb file.

ActiveSupport::Inflector

Before we understand the inflection rules, let’s take a look at the ActiveSupport::Inflector module.

module ActiveSupport
  module Inflector
    extend self

    # ...

    def pluralize(word, locale = :en)
      apply_inflections(word, locale, :plurals)
    end

    def singularize(word, locale = :en)
      apply_inflections(word, locale, :singulars)
    end

    # ...

    private

    def apply_inflections(word, locale, type)
      result = word.to_s.dup
      inflections(locale).send(type).each { |(rule, replacement)| break if result.gsub!(rule, replacement) }
      result
    end

    def inflections(locale)
      @inflections[locale] ||= begin
        require "active_support/inflector/inflections"
        Inflections.new
      end
    end
  end
end

This API is responsible for transforming words from singular to plural, class names to table names, modularized class names to ones without, and class names to foreign keys.

Pluralization

To pluralize a word in the Rails application, we can use the pluralize method.

# It's as simple as
"person".pluralize # => "people"

Singularization

Similarly, we can use the singularize method to singularize a word.

"person".singularize # => "person"

There are a lot of other methods such as humanize, titleize, parameterize that we will not be looking at in this post. For more details, you can check out the Inflector API.

Inflections Rules

To understand the different inflection rules, we’ll be using some examples.

Irregular Inflections

Irregular inflections are words that do not follow the regular pluralization pattern. Let’s assume we want to pluralize the word foot to feet and tooth to teeth. Let’s try doing that in our Rails console:

irb(main):013:0> "foot".pluralize
=> "foots"
irb(main):014:0> "tooth".pluralize
=> "tooths"
irb(main):015:0> 

As expected, the words are not pluralized correctly. We can fix this by adding the following rules in our inflections.rb file.

# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.irregular "foot", "feet"
  inflect.irregular "tooth", "teeth"
end

Now, let’s try again in the Rails console:

irb(main):013:0> "foot".pluralize
=> "feet"
irb(main):014:0> "tooth".pluralize
=> "teeth"
irb(main):015:0> 

There are also plural and singular rules which are similar to the irregular rules.

# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.plural "foot", "feet"
  inflect.plural "tooth", "teeth"
  inflect.singular "feet", "foot"
  inflect.singular "teeth", "tooth"
end

Uncountable Inflections

Uncountable inflections are words that cannot be pluralized.

For this, we’ll take only one example, let’s assume we have a ShoppingList model which has item and count as attributes. The item attribute can be one of the following: apple, banana, milk, bread, and eggs. The count attribute is the number of the given item we want in the shopping list. Now if we want to pluralize the item based on the count we would do the following:

# app/models/shopping_list.rb
class ShoppingList < ApplicationRecord
  def items
    "#{count} #{item.pluralize(count)}"
  end
end

Now if we try to pluralize the item, we would get the following:

irb(main):003:0> ShoppingList.new(item: "apple", count: 2).items
=> "2 apples"
irb(main):004:0> ShoppingList.new(item: "milk", count: 1).items
=> "1 milk"
irb(main):005:0> ShoppingList.new(item: "milk", count: 3).items
=> "3 milks"
irb(main):006:0> 

Again, as expected, the pluralization is not correct for the word milk. Since milk is uncountable, we will need to add a rule for it.

# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.irregular "foot", "feet"
  inflect.irregular "tooth", "teeth"
  inflect.uncountable "milk"
end

Now, if we were to pluralize milk:

irb(main):001:0> ShoppingItem.new(item: "milk", count: 3).items
=> "3 milk"

Acronym Inflections

Acronym inflections are words that are written in all caps. We can specify inflector rules for these words as well. Let’s take the example of HTML5 as an acronym. Without specifying the rules, if we were to use some of the inflector methods on HTML5, we would get some incorrect values:

irb(main):001:0> "html5".camelize
=> "Html5"
irb(main):002:0> "html5".titleize
=> "Html5"

To fix this, we need to specify HTML5 as an acronym.

# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.irregular "foot", "feet"
  inflect.irregular "tooth", "teeth"
  inflect.uncountable "milk"
  inflect.acronym "HTML5"
end

Now, if we were to run the same methods:

irb(main):001:0> "html5".camelize
=> "HTML5"
irb(main):002:0> "html5".titleize
=> "HTML5"
irb(main):003:0> 

Conclusion

In this post, we looked at the ActiveSupport::Inflector module and its different methods. We also looked at the different inflection rules and how to use them in our inflections.rb file.

References

Need help on your Ruby on Rails or React project?

Join Our Newsletter