bitfluent

Kamal Fariz Mahyuddin on Ruby, Rails, Git, Chef and other web development geekery.

I'm available for hire for Ruby and Rails development and training, and infrastructure automation with Chef worldwide.

Email me today.

You should follow me on twitter here.
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?

Fork me on GitHub