belongs_to关联的验证错误消息变得简单

时间:2016-08-18 13:14:05

标签: ruby-on-rails validation

我的应用程序中有一些belongs_to关联,其中一些是可选的(即关联可能是nil),一些是必需的(关联必须是有效的父记录。

我最初的方法是使用我自己的验证方法验证给定的id(这里是强制关联)

belongs_to :category

validates :category_id, 
  presence: true

validate given_category_exists

def given_category_exists
  if category_id.present?
    errors.add( :category_id, 'must be present' ) \
      Category.exists?( category_id )
  end
end

然后我发现Rails会为我做这个,如果我会在关联上使用状态检查,那么我可以省略我自己的验证方法:

belongs_to :category

validates :category,
  presence: true

但是现在,生成的错误消息只会说明:Category can't be blank。这里的问题是:(1)我能提供更有用的信息吗? (2)如何为属性插入自己的翻译? Category是从validates方法生成的默认标签,can't be blank是以下内容的默认错误文本:

另一个问题是:表单中的相关输入字段未标记为“field_with_errors”,因为此字段使用属性的名称标识,而不是关联名称。

使用标准的处理方式,我会在I18n翻译文件中添加一个额外的属性作为关联category的名称,并添加标准消息的替换:

en:
  activerecord:
    models:
      attributes:
        my_model:
          category_id: 'This Category'
          category:    'This Category'

    errors:
      models:
        my_model:
          attributes:
            category:
              blank:  'must be specified.'

很多行都可能出错。而且我不喜欢添加表面属性的想法,这些属性实际上不是属性,而是关联的名称。

有更简单的方法吗?

2 个答案:

答案 0 :(得分:2)

帖子很旧但我仍然会写我的解决方案。 Rails 5有一个required错误密钥,您可以使用它来覆盖那些属于关联的验证消息:

class MyModel < ApplicationRecord
  belongs_to :category
end

请注意,您实际上并不需要在此处指定验证规则(validates :category, presence: true)。要自定义您的消息,只需使用required键:

en:
  activerecord:
    errors:
      models:
        my_model:
          attributes:
            category:
              required: "The category must be specified."

答案 1 :(得分:-1)

我的解决方案覆盖了errors.add方法,该方法被证明非常简单且非常有效。 Rails关联包含所需的所有信息,我只需要在那里找到它。我甚至可以使用对关联的class_name的引用来格式化我自己的错误消息!现在我的错误消息如下所示:

This Category must be one of the existing Categories.
  1. 添加新的标准错误消息:

    en:
      messages:
        blank_assoc: 'must be one of the existing %{assoc}'
    
  2. 将以下文件添加到app / models / concerns文件夹

    module ActiveModelErrorsAdd
      def add( attribute, message = :invalid, options = {})
            if attribute != :base # that's the only other attribute I am using
          all_assocs = @base.class.reflect_on_all_associations( :belongs_to )
          this_assoc = nil
          all_assocs.each do |a|
            if a.name == attribute
              this_assoc = a
              break
            end
          end
        end
        if this_assoc.nil? # just use the standard
          super
        elsif message == :blank # replace with my own
          super( this_assoc.foreign_key, :blank_assoc,
            options.merge( assoc: this_assoc.klass.model_name.human ))
        else # use standard message but refer to the foreign_key!
          super( this_assoc.foreign_key, message, options )
        end
      end
    end
    
    class ActiveModel::Errors
      prepend ActiveModelErrorsAdd
    end
    
  3. 将此文件包含在需要的模型中,您将拥有所有belongs_to关联的错误消息。享受!

  4. 注意:此方法还会将正确的输入字段标记为“field_with_errors” - 即使它具有非标准外键!