Codebeef

Removing duplicate error messages in Rails

If you have a number of validations on a model, then you can quickly end up with something like this appearing in your error blocks:

I'd prefer to see only one error message for each attribute:

This can be achieved by creating an errors_helper.rb file in your apps helpers folder, and pasting the following code (mercilessly modified from this post by Bert over on RailsForum):

module ErrorsHelper

  def error_messages_for(*params)
    options = params.extract_options!.symbolize_keys

    if object = options.delete(:object)
      objects = Array.wrap(object)
    else
      objects = params.collect {|object_name| instance_variable_get("@#{object_name}") }.compact
    end

    count  = objects.inject(0) {|sum, object| sum + object.errors.count }
    unless count.zero?
      html = {}
      [:id, :class].each do |key|
        if options.include?(key)
          value = options[key]
          html[key] = value unless value.blank?
        else
          html[key] = 'errorExplanation'
        end
      end
      options[:object_name] ||= params.first

      I18n.with_options :locale => options[:locale], :scope => [:activerecord, :errors, :template] do |locale|
        header_message = if options.include?(:header_message)
          options[:header_message]
        else
          object_name = options[:object_name].to_s
          object_name = I18n.t(object_name, :default => object_name.gsub('_', ' '), :scope => [:activerecord, :models], :count => 1)
          locale.t :header, :count => count, :model => object_name
        end
        message = options.include?(:message) ? options[:message] : locale.t(:body)
        
        error_messages = objects.sum do |object|
          object.errors.on(:name)
          full_flat_messages(object).map do |msg|
            content_tag(:li, ERB::Util.html_escape(msg))
          end
        end.join.html_safe

        contents = ''
        contents << content_tag(options[:header_tag] || :h2, header_message) unless header_message.blank?
        contents << content_tag(:p, message) unless message.blank?
        contents << content_tag(:ul, error_messages)

        content_tag(:div, contents.html_safe, html)
      end
    else
      ''
    end
  end
  

  ####################
  #
  # added to make the errors display in a single line per field
  #
  ####################
  def full_flat_messages(object)
    message_bucket = {}
    full_messages = []

    object.errors.each do |error|
      if message_bucket[error[0].to_sym].nil?
        message_bucket[error[0].to_sym] = true
        
        full_messages << (error[0]).titleize + ' ' + error[1]
      end
    end
    full_messages
  end

end

Next post

Bundler no metadata found problem

On installing bundler, and getting into Rails 3.0.0, I began to get the following error when running bundle install:

Read More →