A gentle reminder about pluralizations

— May 17, 2006 at 10:46 PDT


Watching the RSS feed from the Ruby on Rails trac is a great way to keep up on what's happening in Rails development. If you're doing any development on the Ruby on Rails project it's required reading. Even if you just are using Rails for a web app, it's useful to keep up on what bugs people are reporting.

Lately I've noticed a slew of bugs being opened against the Inflector, the class in Rails that transforms words from one form to another: singular to plural, classname to tablename, etc. The bugs all complain that Inflector is getting a pluralization or singularization wrong. But this isn't a bug in Inflector, it is just an inherent limitation of how it works. But fear not, there is a better solution than opening a bug against the Inflector.

I guess this has been a constant thing over the history of Rails, but since it's still going on, it deserves a rehash.

Class Inflector has a bunch of regular expressions it uses to match a word then transform it from singular to plural or plural to singular. It's a pretty clever but fundamentally limited piece of code, as it relies on a list of special cases to do its work.

You can see all the standard rules for pluralization and singularization in inflections.rb in the ActiveSupport library. Notice there are only 18 rules for pluralization, which is not going to cover all the vagaries of the English language. Given the highly irregular nature of English, it would be a daunting task to create an exhaustive list of rules for pluraliztion, and that's even ignoring neologisms and ad-hoc corruptions. Rails solves the problem by allowing each project to define its own set of custom rules for singular and plural forms.

If the inflector is not handling any of your model names correctly, don't open a bug on it. Instead, go to the environments.rb file in your project and add your own rules for the names of the models in question.

At the end of environments.rb you'll see the following commented out block of code:

# Inflector.inflections do |inflect|
#   inflect.plural /^(ox)$/i, '\1en'
#   inflect.singular /^(ox)en/i, '\1'
#   inflect.irregular 'person', 'people'
#   inflect.uncountable %w( fish sheep )
# end

Uncomment the block and put your own rules in it. See the docs on Inflections for the detailed API.

Inflector.inflections do |inflect|
  inflect.irregular 'leaf', 'leaves'
  inflect.irregular 'staff', 'staves'
end

The irregular method is most convenient to create a rule for a particular word. If you want to use a regular expression for several similar words, use the plural and singular methods (you need a matched set of them both, or only one direction will work). And of course uncountable indicates a word is the same in both singular and plural forms.

So that's it. Don't be creating any more pluralization bug tickets. Just use the handy Inflector interface to customize pluralizations for yourself.

7 commentsrails

Comments
  1. Andre Lewis2006-05-17 13:29:31

    Thanks for the tip Josh. I was recently working with a "Cafe" model, which the inflector pluralizes to "Caves" :-)

  2. Josh Susser2006-05-17 13:33:38

    Andre, that seems sort of apropriate, given some of the cavelike cafes in this town...

  3. Joshua Wehner2006-05-17 16:08:55

    I can't help but feel like you're leaving out the clincher, though. I get that maintaining a perfect list would be impossible for the core team, but I don't get why they don't accept patches against Inflector for these things. In other words, you haven't explained why they wouldn't let the "lazyweb" do the impossible thing for them.

    Or, to put it another way, there are some irregulars already coded, yes? Why stop at the words currently covered? What makes them any better than the new(er) words?

  4. carmen2006-05-18 05:52:06

    easy to tweak but, isnt there a stemming library or something that solved this problem 12 or 15 years ago? wordnet? i know a lot of perl apps bring in Lingua:: for example, maybe its just a big project that needs a port to ruby or the core team prefers simple solutions over added dependencies..

  5. Josh Susser2006-05-18 08:22:27

    @Joshua Wehner: The decision to freeze the pluralizer happened before I got involved with Rails, so I'm not certain of the details, but I gather dealing with all the increasingly frequent requests for new plurals was too distracting. The Rails team never tries to be all things to all people, and letting people add customizations to their own configuration is the Rails way of dealing with that sort of thing. Just my opinion: Perhaps every now and then there could be some kind of bulk upgrade of the list of pluralizations, which would keep the distraction low and still let Rails grow to include commonly requested cases.

    @carmen: Perhaps a stemmer would improve the base set of pluralizations, but I doubt it would be perfect (I've worked with such things before) and so there would still need to be a way to customize your configuration for special cases. But I think you're right about the core team preferring simple and "good enough" over added dependencies and "not perfect either".

  6. RSL2006-06-02 04:33:25

    I agree that a lot of the "bugs" are, in fact, the way the Inflector is supposed to work. However, as I've said on a couple of different sites, the idea that "pages".pluralize doesn't return "pages" [since it was already plural] but "page" [a singular form!] is a bit unexpected and completely violates Matz's principle of least surprise. Sure, you can find an absolute plural of a string by saying String#classify#pluralize [or String#classify.pluralize or whatever is the right notation there] but if String#classify always returns a singular form why is it too much to ask for String#pluralize to always return a plural one?

  7. Joseph2006-07-07 21:58:07

    fyi, the mirror of this article on Riding Rails is broken right now.

Sorry, comments for this article are closed.