bitfluent

Kamal Fariz Mahyuddin on Ruby, Rails, Apple and being a Dad.

Reach me by email.

Mar
8th
Sat
permalink

On Providing Alternate Labels to ActiveRecord Attributes

I cooked up a simple enhancement to ActiveRecord::Errors#full_messages to allow me to pass a mapping of attribute to label. Here’s the snippet:

module ActiveRecord
  class Errors
    def full_messages_with_attr_mapping(mappings)
      mappings.symbolize_keys!
      full_messages = []

      @errors.each_key do |attr|
        @errors[attr].each do |msg|
          next if msg.nil?

          if attr == "base"
            full_messages << msg
          else
            full_messages << (mappings[attr.to_sym] || @base.class.human_attribute_name(attr)) + " " + msg
          end
        end
      end
      full_messages
    end
  end
end

Pastie Link

Let me walk through the scenario where I found this snippet useful.

Suppose I had a User model with the field ic to store the Malaysian National Registration Identification Card number. If I hit validation errors, I’ll get an ugly error message when I use @user.errors.full_messages.each { ... }

Ic is not valid.

With the snippet above, I’ll call it with @user.errors.full_messages_with_attr_mapping(:ic => 'I/C Number').each { ... } and get

I/C Number is not valid.

Much nicer.

However, I don’t like this solution much because I can’t alias_method_chain this to full_messages (because of the explicit mapping params). The downside of this is @user.errors.each_full { ... } will not do what I want as it uses full_messages.

Ideally, I want something that looks like:

class User < ActiveRecord::Base
  attr_label :ic => 'I/C Number', :hp => 'H/P Number'
  validates_mykad_of :ic
  ...
end

or, we can add a new key to specify the preferred label, much like how validates_* lets you override the error message.

class User < ActiveRecord::Base
  validates_mykad_of :ic, :message => 'is not valid', :label => 'I/C Number'
  ...
end

Or something like that.

I prefer Option 1 as it opens up more than just validation error messages. Other places it’ll be useful is in forms

<% form_for :user do |f| %>
  <%= f.label :ic %>
<% end %>

Is there a better way? Are there plugins that allow one to do this already?