2011-05-09 8 views
5

tengo los siguientes modelos:reprimir "base" en el texto de error de validación personalizada de rieles anidados atributos

class Evaluation < ActiveRecord::Base 
    attr_accessible :product_id, :description, :evaluation_institutions_attributes 

    has_many :evaluation_institutions, :dependent => :destroy 
    accepts_nested_attributes_for :evaluation_institutions, :reject_if => lambda { |a| a[:token].blank? }, :allow_destroy => true  

    validate :requires_at_least_one_institution 

    private 

     def requires_at_least_one_institution 
     if evaluation_institution_ids.nil? || evaluation_institution_ids.length == 0 
      errors.add_to_base("Please select at least one institution") 
     end 
     end  
end 

class EvaluationInstitution < ActiveRecord::Base 

    attr_accessible :evaluation_institution_departments_attributes, :institution_id 

    belongs_to :evaluation 

    has_many :evaluation_institution_departments, :dependent => :destroy 
    accepts_nested_attributes_for :evaluation_institution_departments, :reject_if => lambda { |a| a[:department_id].blank? }, :allow_destroy => true 

    validate :requires_at_least_one_department 

    private 

    def requires_at_least_one_department 
     if evaluation_institution_departments.nil? || evaluation_institution_departments.length == 0 
     errors.add_to_base("Please select at least one department") 
     end 
    end 

end 

class EvaluationInstitutionDepartment < ActiveRecord::Base 
    belongs_to :evaluation_institution 
    belongs_to :department 
end 

que tengo una forma de evaluación que incluye atributos anidados para EvaluationInstitution y EvaluationInstitutionDepartment, por lo que mi forma se anida a 3 niveles El 3er nivel me está dando un problema.

Los errores son provocados como se esperaba, pero cuando el error desencadena por requires_at_least_one_department, dice el texto de base

instituciones de evaluación Por favor seleccione al menos un departamento de

El mensaje debe decir "Por favor, seleccione al menos un departamento ".

¿Cómo elimino "Evaluation institutions base"?

+0

¿Alguna vez encontró una respuesta a esto @Kevin? Estoy teniendo el mismo problema. ¿Se pregunta si la simplificación de la pregunta podría ayudar ...? –

+0

Nunca encontré una respuesta a esto. – Kevin

+0

@paul, por cierto, mi trabajo fue impulsar toda la validación hasta el modelo de nivel superior, la evaluación. Entonces, por ejemplo, mi función: require_at_least_one_department se mueve al modelo de Evaluación. No es una solución excelente. – Kevin

Respuesta

6

En Rails 3.2, si observa la implementación del método full_message, verá que muestra mensajes de error a través de I18n con el formato "% {attribute}% {message}".

Esto significa que se puede personalizar el formato que se muestra en sus locales I18n de la siguiente manera:

activerecord: 
    attributes: 
    evaluation_institutions: 
     base: '' 

Eso sería deshacerse del prefijo "base de instituciones de evaluación" como lo hubiera querido.

+0

No sé por qué he votado a favor. No puedo conseguir que esto funcione. Parecía una solución decente. –

+0

Hice que el mío funcionara al eliminar la 2da línea en ese archivo de configuraciones regionales ... en otras palabras, no incluya "errores" en el archivo yaml. –

+0

Para mí tuve que usar el nombre del modelo en el local en forma singular no pluralizada, es decir: evaluation_institution –

1

Añadiendo el siguiente parche mono a inicializadores hicieron el trabajo para mí en 3.2.3 con dynamic_form:

class ActiveModel::Errors 
    #exact copy of dynamic_form full_messages except 'attr_name = attr_name.sub(' base', ':')' 
    def full_messages   
    full_messages = [] 

    each do |attribute, messages| 
     messages = Array.wrap(messages) 
     next if messages.empty? 

     if attribute == :base 
     messages.each {|m| full_messages << m } 
     else 
     attr_name = attribute.to_s.gsub('.', '_').humanize 
     attr_name = @base.class.human_attribute_name(attribute, :default => attr_name) 
     attr_name = attr_name.sub(' base', ':') 
     options = { :default => "%{attribute} %{message}", :attribute => attr_name } 

     messages.each do |m| 
      if m =~ /^\^/ 
      options[:default] = "%{message}" 
      full_messages << I18n.t(:"errors.dynamic_format", options.merge(:message => m[1..-1])) 
      elsif m.is_a? Proc 
      options[:default] = "%{message}" 
      full_messages << I18n.t(:"errors.dynamic_format", options.merge(:message => m.call(@base))) 
      else 
      full_messages << I18n.t(:"errors.format", options.merge(:message => m)) 
      end    
     end 
     end 
    end 

    full_messages 
    end 
end 

Si no está utilizando dynamic_form, pruebe lo siguiente en su lugar (a menos que su forma de joya anula errores. full_messages como dynamic_form hace):

class ActiveModel::Errors   
    #exact copy of Rails 3.2.3 full_message except 'attr_name = attr_name.sub(' base', ':')' 
    def full_message(attribute, message) 
     return message if attribute == :base 
     attr_name = attribute.to_s.gsub('.', '_').humanize 
     attr_name = @base.class.human_attribute_name(attribute, :default => attr_name) 
     attr_name = attr_name.sub(' base', ':') 
     I18n.t(:"errors.format", { 
     :default => "%{attribute} %{message}", 
     :attribute => attr_name, 
     :message => message 
     }) 
    end 
end 

el único cambio al código original es la siguiente línea:

attr_name = attr_name.sub(' base', ':') 

Sugerencias bienvenidas.

2

Si alguien está buscando una solución para esto que no implique parche de mono, esto es lo que hice parcialmente en mis errores. Simplemente busco "base" en el nombre del atributo con el error y si existe, solo publico el mensaje, de lo contrario construyo el full_message. Ahora esto no funcionará si tienes atributos que tienen base en el nombre, pero no lo hago, así que esto funciona para mí. Es un poco raro, pero también lo son las otras soluciones a este problema.

<% if object.errors.any? %> 
    <div id="error-explanation"> 
    <div class="alert alert-error"> 
     <ul> 
     <% object.errors.each do |atr, msg| %> 
      <li> 
      <% if atr.to_s.include? "base" %> 
       <%= msg %> 
      <% else %> 
       <%= object.errors.full_message(atr, msg) %> 
      <% end %> 
      </li> 
     <% end %> 
     </ul> 
    </div> 
    </div> 
<% end %> 
+0

Gracias. Hice algo bastante similar (Rails 4) pero con este control menos hacky: 'si atr ==: base || atr.to_s.ends_with? (".base") ' –

Cuestiones relacionadas