Skip to content

human_name and error_message_for controversy

Parace que nuestros amigos ActiveRecord::Base.human_name y ActionView::Base::Helpers.error_messages_for parece que no están en la misma onda o ola o como queráis. El método human_name intenta proporcionar un nombre más “humano” a nuestros modelos de active record y error_messages_for intenta proporcionarnos unos bonitos mensajes de error al intentar crear/editar nuestro modelo de active record.

Además error_messages_for tiene multitud de opciones que nos permiten definir enteramente el contenido de los mensajes, su estructura html y otras cosillas. Pero el problema viene cuando tratamos con los valores por defecto. Este método captura la variable de instancia a partir de su primer parámetro y debe obtener la variable options[object_name] de dicha variable si la opción object_name no es pasada como parámetro. Y aquí llegamos a la controversia, ¿Que clave de nuestros locale recuperamos para generar el object_name en caso de que no lo proporcione el programador?

Pues como suponéis error_messages_for no recupera la misma clave que human_name con lo que nos surge un problema.

def error_messages_for(*params)
   options[:object_name] ||= params.first
   ...
     I18n.with_options :locale => options[:locale], :scope => [:activerecord, :errors, :template] do |locale|
       ...
       object_name = options[:object_name].to_s.gsub('_', ' ')
       object_name = I18n.t(object_name, :default => object_name, :scope => [:activerecord, :models], :count => 1)
       ...
     end
   ...
 end


 def human_name(options = {})
   defaults = self_and_descendants_from_active_record.map do |klass|
     :"#{klass.name.underscore}"
   end
   defaults << self.name.humanize
   I18n.translate(defaults.shift, {:scope => [:activerecord, :models], :count => 1, :default => defaults}.merge(options))
 end

Pero ante la llegada inminente de Rails 3 o eso nos comentaba Yehuda en el grupo del core team se han puesto de acuerdo estos muchachos con la ayuda de ActiveModel y tenemos esto.

module ActiveModel::Naming
   # Transform the model name into a more humane format, using I18n. By default,
   # it will underscore then humanize the class name (BlogPost.model_name.human #=> "Blog post").
   # Specify +options+ with additional translating options.
   def human(options={})
     # No nos interesa que clave recupera pero vemos que será la misma
     ...
   end
 end

 module ActionView
   module Helpers
     module ActiveModel

       def error_messages_for(*params)
         ...
         if object.class.respond_to?(:model_name)
           options[:object_name] ||= object.class.model_name.human.downcase
         end
         ...
       end
     end
   end
 end

Así por ahora solo nos queda esperar o pasarle a error_messages_for el parámetro object_name con le valor que necesitemos.

Ciau