禁止显示错误文本中的"base",以便自定义验证 Rails 嵌套属性



我有以下型号:

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

我有一个评估表单,其中包含评估机构和评估机构部门的嵌套属性,因此我的表单嵌套为 3 个级别。 第三关给我一个问题。

错误

按预期触发,但当错误触发requires_at_least_one_department时,文本显示

评估机构基地请 至少选择一个部门

该消息应为"请至少选择一个部门"。

如何删除"评估机构基础"?

在 Rails 3.2 中,如果你看一下方法 full_message 的实现,你会发现它通过 I18n 显示错误消息,格式为"%{attribute} %{message}"。

这意味着您可以在 I18n 语言环境中自定义显示的格式,如下所示:

activerecord:
  attributes:
    evaluation_institutions:
      base: ''

这将摆脱您想要的前缀"评估机构基础"。

如果有人正在寻找不涉及猴子修补的解决方案,这是我在错误部分中所做的。我只是在带有错误的属性名称中查找"base",如果存在,我只发布消息,否则我构建full_message。现在,如果您有名称中包含 base 的属性,这将不起作用,但我不这样做,这对我有用。这有点笨拙,但这个问题的其他解决方案也是如此。

<% 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 %>

将以下猴子补丁添加到初始值设定项中为我完成了 3.2.3 中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

如果您不使用dynamic_form,请尝试以下操作(除非您的表单 Gem 像 dynamic_form 一样覆盖errors.full_messages):

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

对原始代码的唯一更改是以下行:

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

欢迎提出建议。

这是一个较老的问题,但这个问题只是在 Rails 6 中再次咬了我,所以在这里发布我的解决方案,因为这是涵盖该问题的最相关的 SO 帖子。

示例:保存顶级类:"Parent"包含"Child"集合,其中"Child"具有自定义验证方法:

例如

class Parent < ActiveRecord::Base
  has_many :children
    accepts_nested_attributes_for :children, allow_destroy: true, reject_if: :all_blank
end
class Child < ActiveRecord::Base
  belongs_to :parent
  validate :custom_method
  def custom_method
    errors.add(:base, :error_symbol)
  end
end

需要以下内容:

  1. 为"error_symbol"提供区域设置条目
  2. 防止将子项呈现为"子基数..."的错误
<小时 />

溶液

首先,将config.active_model.i18n_customize_full_message = true添加到 application.rb 文件中。

然后,以下区域设置文件用于覆盖消息并防止将"Base"附加到集合前面。

# config/locales/en.yml
en:
  activerecord:
    errors:
      models:
        parent/children:
          format: 'Child: %{message}'
        child:
          error_symbol: "Error message goes here"

有趣的是,这里似乎与accepts_nested_attributes_for有一些交互,因为我只能在使用单个参数对象创建父项和子项时重现此问题。

如果这对您不起作用,或者您有更复杂的问题,请查看ActiveModel/lib/active_model/errors.rb full_message方法。

这应该告诉您是否:

  1. 有问题的类正确选取该类的 i18n 格式
  2. 它使用哪些键在区域设置文件中查找。

相关内容

  • 没有找到相关文章