Take the 2-minute tour ×

Using Rails 3.1.3. I have Accounts and Users. One Account can have many Users. I set this up using accepts_nested_attributes_for as described in this answer.

I have a new.html.erb view that accepts data for one account and one user at the same time. (The user's data goes into a "subform.") The form works fine. However if there is an error, the messages for the subform's fields are pluralized, even though they should be singular. For example, I get

Users password doesn't match confirmation
Users password is too short (minimum is 8 characters)

instead of

User password doesn't match confirmation
User password is too short (minimum is 8 characters)

I don't think this is an inflection issue, since "User" follows standard pluralization rules. Rather it must have to do with the use of nested attributes in a subform. In my case, the subform returns an array containing one user, but theoretically it could return data for multiple users.

How/where can I tell Rails not to pluralize when referring to only one element of an array?

Edit 3/14/2012 to show controller and view:

app/controllers/accounts_controller.rb ("New" action only):

class AccountsController < ApplicationController
  before_filter :authenticate_user!, :except => [:new, :create]
  before_filter :user_signed_out,    :only   => [:new, :create]
  load_and_authorize_resource # CanCan - does a standard load for each action, and authorizes user

  def new
    # CanCan:  @account = Account.new (and tests each attribute for ability)
    @title = "Sign Up for a New Account"
    @header = "Sign up for a new account"


<h2><%= @header %></h2>

<%= form_for(@account) do |f| %>
  <%= render 'account_fields', :f => f %>

  <%= f.fields_for :users do |user_form| %>
    <div class="field"><%= user_form.label :email %><br />
    <%= user_form.email_field :email %></div>
    <div class="field"><%= user_form.label :password %><br />
    <%= user_form.password_field :password %></div>
    <div class="field"><%= user_form.label :password_confirmation %><br />
    <%= user_form.password_field :password_confirmation %></div>
  <% end %>

  <div class="actions">
    <%= f.submit "Create Account" %>
<% end %>

I was trying error_messages_for inside the f.fields_for block above.

app/views/shared/_error_messages.html.erb rendered by layout before all views:

<% if object.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(object.errors.count, "error") %> 
      prohibited this <%= object.class.to_s.underscore.humanize.downcase %>
      from being saved:</h2>
    <% object.errors.full_messages.each do |msg| %>
    <% end %>
<% end %>
share|improve this question
add comment

2 Answers

This is happening because it's a has_many association. What you can do to override the object name that's render is to pass this option like so:

<%= error_messages_for @account, :object => [@account, :users], :object_name => 'Account' %>

This allows you to change that label to whatever you want for example:

<%= error_messages_for @account, :object => [@account, :users], :object_name => 'Profile' %>

Which then would look like

Profile password doesn't match confirmation
Profile password is too short (minimum is 8 characters)


share|improve this answer
Interesting idea, but it seems that f.error_messages was removed from Rails 3 so I wasn't able to test it. I've since added SimpleForm and Twitter Bootstrap, which puts a highlight box around the form field containing the error and adds only the suffix of the error text. I.e. it's a workaround that avoids the issue by not actually naming the object. –  Mark Berry Mar 13 '12 at 21:39
Nope it's still available. the f. is the variable that's passed into your form_for. Try my edit above. –  Marc Mar 14 '12 at 2:35
Okay I reverted my code to make sure I could duplicate the problem. Then I added <%= error_messages_for @user, :object_name => 'User' %> to the subform and got undefined method 'error_messages_for' for #<#<Class:0xa273774>:0xa278328>. This seems to confirm what I saw in several articles, e.g. No more error_messages_for in Rails 3. Even if it did work, I didn't want to change it to "Profile", I just wanted to get it to do correct pluralization: if there was only one user in the array, don't pluralize to "users". –  Mark Berry Mar 14 '12 at 19:26
Can I see the full _form.erb.html and your controller? –  Marc Mar 15 '12 at 1:22
Added to original question. Also added the error_messages partial from which the object.errors.full_messages are displayed. –  Mark Berry Mar 15 '12 at 3:15
show 5 more comments
up vote 0 down vote accepted

As @Marc suggested, the messages are generated based on the model. This gets tricky when accepts_nested_attributes_for is involved, as it is in my Account model:

has_many :users, :inverse_of => :account, :dependent => :destroy
accepts_nested_attributes_for :users

To get more insight into the error object, I inserted <%= object.errors.inspect %> into _error_messages.html.erb. This showed me that the full error object is, for example:

#<ActiveModel::Errors:0xb5c86a8 @base=#<Account id: nil, name: "", created_at: nil, updated_at: nil>, @messages={:"users.password"=>["doesn't match confirmation", "is too short (minimum is 8 characters)"], :name=>["can't be blank"]}>

When Rails generates the full_messages array, it just feeds each attribute and message into the full_message method. If the attribute is "users.password", for example, then that will simply be "humanized" (without respect to the number of objects in the array) and concatenated with the message(s) to return

Users password doesn't match confirmation
Users password is too short (minimum is 8 characters)

The crux of any solution is to avoid using full_messages:

  • Although I couldn't get error_messages_for to work, it wouldn't be too hard to write a small helper that allows specifying a custom object name to prepend to the message.

  • Avoid the problem of the displaying object name altogether by highlighting the specific field that is in error and placing the error message suffix(es) next to the field. This works nicely with Twitter Bootstrap and SimpleForm.

  • This article make a good case for providing explicit translations for each message, claiming that any attempt to concatenate strings is bound to cause problems.

share|improve this answer
add comment

Your Answer


