【问题标题】:How to change validation error messages for associations?如何更改关联的验证错误消息?
【发布时间】:2013-11-19 12:43:04
【问题描述】:

我有一个Document 类,带有has_many :fields。每个 Field 对象都有一个name 属性。

当我验证文档和关联的字段时,对于每个无效的字段关联,我都会收到以下验证错误消息:

Fields is invalid.

这是一个非常无用的错误消息。相反,我希望它说:

Field '<value of the name attribute>' is invalid.

例如:

Field 'subject' is invalid.
Field 'date' is invalid.

我该怎么做?

【问题讨论】:

    标签: ruby-on-rails activerecord ruby-on-rails-4


    【解决方案1】:

    我也有同样的问题。目前还没有好的答案。

    所以我自己解决了这个问题,将关联错误消息替换为详细错误消息:

    创建关注文件app/models/concerns/association_error_detail_concern.rb:

        module AssociationErrorDetailConcern
          extend ActiveSupport::Concern
        
          included do
            after_validation :replace_association_error_message
          end
        
          class_methods do
            def association_names
              @association_names ||= self.reflect_on_all_associations.map(&:name)
            end
          end
        
       
          def replace_association_error_message
     
            # Gets the intersection between this class's associations and the instance's associations that have validation errors
            associations_with_errors = self.errors.keys & self.class.association_names
        
            associations_with_errors.each do |association_name|
              next unless self.errors[association_name]
              self.errors.delete(association_name)
              Array.wrap(public_send(association_name)).each do |record|
                record.errors.each do |attribute, error|
                  self.errors.add(:"#{association_name}.#{attribute}", error)
                end
              end
            end
          end
        end
    

    然后将其包含在您的模型中:

    class Shop::Product < ApplicationRecord
      include AssociationErrorDetailConcern
      ...
    end
    

    那我们来说说这些属性的翻译。

    Rails 将自动采用相关模型的翻译中定义的那些:

      activerecord:
        attributes:
          associated_model_name:
            attribute_name: 'Foo'
    

    但是,可能需要使该属性在关联上下文中验证时具有不同的翻译。在验证用户时,您可能希望显示Poster's e-mail is required 之类的内容,而不是只显示Email is required,而在验证Post 时显示belongs_to :user

    考虑到上述问题,由于错误将被添加到键 :user.email,Rails 会找到 activerecord.attributes.user.email 的翻译,但它也会首先查找 activerecord.attributes.post/user.email,如下所示:

      activerecord:
        attributes:
          post/user:
            email: 'Foo'
    

    这为您翻译这些属性提供了最大的灵活性,具体取决于验证它们的上下文。

    如果您想了解 Rails 是如何找到这些密钥的,请查看 translation.rb#human_attribute_name,您会看到它会在 . 处拆分密钥并使用它在 .yml 文件中查找密钥.

    EDITOR="sublime --wait" bundle open activemodel

    最后但同样重要的是,不要忘记 Rails 只会自动验证您的关联,如果它是 has_manyhas_and_belongs_to_many(检查每个关联类型 validate 上的 validate 选项https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html)。

    belongs_tohas_one 有一个默认的validate: false,您可以将其更改为true 或使用validates_associated

    在上面的示例中,由于 belongs_to :user 是 Post,因此您必须添加 validates_associated :user 例如,否则用户的验证甚至不会运行。

    【讨论】:

    • 非常关心,我刚刚对其进行了增强,以便它可以与嵌套的 i18n 键一起使用
    【解决方案2】:

    我想已经有人问过这样的问题了。

    看看这个答案可能会有用:

    How can I add a validation error in before_save association callbacks

    或 ruby​​ api 文档:

    http://edgeguides.rubyonrails.org/active_record_validations.html#performing-custom-validations

    【讨论】:

    • 这不是关于自定义验证,而是关于自定义关联的内置验证消息。
    【解决方案3】:

    不幸的是,似乎没有一种简单的方法来自定义自动验证的关联,这绝对是 Rails 可以增强的东西。但是,您可以在 has_many 上关闭关联的自动验证(但请确保以某种方式手动验证它们):

    has_many :fields, validate: false
    

    然后,例如,您可以手动添加通用消息,例如:

    validates_associated :fields, message: "ARE Invalid."
    

    但请注意,这将替换所有字段验证的消息,而不仅仅是“无效”

    如果您需要包含无效名称值的更多自定义消息,则必须在 before_save 挂钩中进行手动验证

    【讨论】:

      【解决方案4】:

      config/locales/en.yml

      en:
        activerecord:
          attributes:
            cricket: #model name 
              game: "" # attribute name ( can be game_id)
          errors:
            models:
              cricket: # model name
                attributes:
                  game: # attribute name
                    required: "Error message has been changed."
      

      【讨论】:

        【解决方案5】:

        将值放入 en.yml 并在错误消息中使用它对我有用,但我也必须提供需要在每个字段名称后附加的静态消息。我找到了一种简单的方法来做到这一点,这样做之后我不必在 en.yml 中放任何东西。改为使用

        validates :field, validates_associated: {message: "%{model} is invalid"}

        您可以尝试以下关键字:

        • 型号
        • 属性
        • 价值

        【讨论】:

          猜你喜欢
          • 2020-08-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-15
          • 2020-08-15
          • 2021-12-30
          • 2015-07-27
          相关资源
          最近更新 更多