Understanding Pluralization Patterns in Rails

Problem

You've noticed that Rails relies heavily on convention. In particular, it often uses pluralization to link the name of a database class to the corresponding model and controller classes. You want to understand where pluralization is used and where it isn't.

Solution

There are three main places in Rails where pluralization conventions are used by default:


Database table names: plural

Database table names are expected to be pluralized. For example, a table containing employee records should be named Employees.


Model class names: singular

Model class names are the singular form of the database table that they are modeling. For example, an Employee model is created based on a table named employees.


Controller class names: plural

Controller class names are pluralized, such as EmployeesController or AccountsController.

Becoming familiar with these three conventions will go a long way toward getting comfortable with Rails. The intent of pluralization is to make your code more readable and transparent. For a good demonstration of how readable Rails code can be, look at the setup of a one-to-many relationship between chapters and recipes:

app/models/chapter.rb:

class Chapter < ActiveRecord::Base
 has_many :recipes
end

This code reads: "A chapter has many recipes." You can see how this goes a long way toward explaining the underlying relationship between chapters and recipes. It's clear enough to nonprogrammers or clients.

There are other places where Rails uses pluralization, including view directory names, functional and unit test filenames, and test fixture filenames.

One of the best ways to get used to pluralization is to experiment with Rails generators while using the --pretend option (or simply -p) when using script/generate to create scaffolding, controllers, or models.

$ ruby script/generate scaffold -p recipe
 exists app/controllers/
 exists app/helpers/
 create app/views/recipes
 exists test/functional/
 dependency model
 exists app/models/
 exists test/unit/
 exists test/fixtures/
 create app/models/recipe.rb
 create test/unit/recipe_test.rb
 create test/fixtures/recipes.yml
 create app/views/recipes/_form.rhtml
 create app/views/recipes/list.rhtml
 create app/views/recipes/show.rhtml
 create app/views/recipes/new.rhtml
 create app/views/recipes/edit.rhtml
 create app/controllers/recipes_controller.rb
 create test/functional/recipes_controller_test.rb
 create app/helpers/recipes_helper.rb
 create app/views/layouts/recipes.rhtml
 create public/stylesheets/scaffold.cs

Rails prints out a dump of all the files it would create, based on the string you pass to it, but it doesn't actually do anything. You can use the --pretend flag to see how and when, Rails pluralizes various words. Lastly, Geoffrey Grosenbach has posted an online tool called The Pluralizer that demonstrates all of Rails' pluralization conventions for a given word. You can find the tool at .

Discussion

Pluralization in Rails is often a hot topic of debate, especially among skeptics who are hunting for fuel for an argument. Pluralization is just one of a number of conventions that Rails uses in an attempt to eliminate much of the configuration normally associated with web development frameworks.

Ultimately, pluralization is just a convention. You can always disable it globally or override it in specific cases. You can turn it off by adding the following to the environment.rb configuration file:

config/environment.rb:

ActiveRecord::Base.pluralize_table_names = false

One problem with pluralization is that not all the words get the correct inflection treatment. The class that decides how to pluralize words is called Inflections. This class defines methods that get mixed into Ruby's String class; these methods are made available to all String objects in Rails. You can experiment with these methods, namely pluralize, directly from the Rails console. For example:

$ ruby script/console
Loading development environment.
>> "account".pluralize
=> "accounts"
>> "people".pluralize
=> "peoples"

Many of the various edge-cases of English pluralization are contained in a file called inflections.rb within the ActiveSupport gem directory. Here's an abbreviated version of that file:

activesupport-1.3.1/lib/active_support/inflections.rb:

Inflector.inflections do |inflect|
 inflect.plural(/$/, 's')
 inflect.plural(/s$/i, 's')
 inflect.plural(/(ax|test)is$/i, '\1es') 
 ...
 inflect.singular(/s$/i, '')
 inflect.singular(/(n)ews$/i, '\1ews')
 inflect.singular(/([ti])a$/i, '\1um')
 ...
 inflect.irregular('person', 'people')
 inflect.irregular('man', 'men')
 inflect.irregular('child', 'children')
 ...
 inflect.uncountable(%w(equipment information rice money species series fish sheep))
end

You may eventually find a specific pluralization rule that is not contained in this file. Let's say, for example, that you have a table containing foo records (each containing a tip aimed at helping newbies become Ruby masters). In this case, the pluralization of foo is just foo, which is not what the pluralize method expects it to be:

$ ruby script/console
>> "foo".pluralize
=> "foos"

Rails calls words that are the same in both plural and singular form uncountable. To add the word foo to a list of all uncountable words, add the following to the bottom of environment.rb:

config/environment.rb:

...
Inflector.inflections do |inflect|
 inflect.uncountable "foo"
end

Reload script/console, pluralize foo again, and you'll find that your new inflection rule has been correctly applied.

$ ruby script/console
>> "foo".pluralize
=> "foo"

Other inflection rules can be added to the block passed to Inflector.inflections. Here are a few examples:

Inflector.inflections do |inflect|
 inflect.plural /^(ox)$/i, '\1\2en'
 inflect.singular /^(ox)en/i, '\1'
 inflect.irregular 'octopus', 'octopi'
 inflect.uncountable "equipment"
end

These rules are applied before the rules defined in inflections.rb. Because of this, you can override existing rules defined by the framework.

See Also