验证与模型的错误消息相关联

时间:2011-09-12 11:58:41

标签: ruby-on-rails validation

我有两个模型如下

class User < ActiveRecord::Base
 validates_associated :account
end

class Account < ActiveRecord::Base

  belongs_to :user

  #----------------------------------Validations--Start-------------------------
  validates_length_of :unique_url, :within => 2..30 ,:message => "Should be atleast 3 characters long!"
  validates_uniqueness_of :unique_url ,:message => "Already Taken"
  validates_format_of :unique_url,:with => /^([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])$/ , :message => " Cannot contain special charaters"
  #----------------------------------Validations--End---------------------------
end

现在,当我将帐户与用户关联时,它会显示

  

“帐户无效”

相反,我希望直接从该模型获取错误消息。 所以应该说

"Should be atleast 3 characters long!""Already Taken"" Cannot contain special charaters"

有办法做到这一点吗?

我不想给出像:

这样的通用消息
validates_associated :account , :message=>"one of the three validations failed"

7 个答案:

答案 0 :(得分:28)

您可以根据内置验证器的代码编写自己的自定义验证器。

查看validates_associated的源代码,我们看到它使用了“AssociatedValidator”。源代码是:

module ActiveRecord
  module Validations
    class AssociatedValidator < ActiveModel::EachValidator
      def validate_each(record, attribute, value)
        return if (value.is_a?(Array) ? value : [value]).collect{ |r| r.nil? || r.valid? }.all?
        record.errors.add(attribute, :invalid, options.merge(:value => value))
      end
    end

    module ClassMethods
      def validates_associated(*attr_names)
        validates_with AssociatedValidator, _merge_attributes(attr_names)
      end
    end
  end
end

因此,您可以使用此示例来创建一个自定义验证程序,以此类似于此错误消息:

module ActiveRecord
  module Validations
    class AssociatedBubblingValidator < ActiveModel::EachValidator
      def validate_each(record, attribute, value)
        (value.is_a?(Array) ? value : [value]).each do |v|
          unless v.valid?
            v.errors.full_messages.each do |msg|
              record.errors.add(attribute, msg, options.merge(:value => value))
            end
          end
        end
      end
    end

    module ClassMethods
      def validates_associated_bubbling(*attr_names)
        validates_with AssociatedBubblingValidator, _merge_attributes(attr_names)
      end
    end
  end
end

您可以将此代码放在初始值设定项中,例如/initializers/associated_bubbling_validator.rb

最后,你会这样验证:

class User < ActiveRecord::Base
 validates_associated_bubbling :account
end

注意:上面的代码是完全未经测试的,但是如果它不能完全正常工作,那么希望能够让你走上正确的轨道

答案 1 :(得分:11)

可能你可以试试下面给出的东西

validates_associated :account , :message=> lambda{|class_obj, obj| obj[:value].errors.full_messages.join(",") }

通过 obj[:value] 您正在访问经过验证的帐户对象。所以obj [:value] .errors会给你错误。

答案 2 :(得分:4)

vanilla解决方案是对关联对象进行第二次错误渲染:

<%= render :partial => 'shared/errors', :locals => {:instance => @account.owner} %>
<%= render :partial => 'shared/errors', :locals => {:instance => @account} %>

答案 3 :(得分:1)

要获取帐户的错误消息,您必须在该实例上调用errors方法:

@user.account.errors

@account = @user.build_account
@account.errors

或在视图中:

<%= error_messages_for :account %>

我假设它是一个has_one关系。

答案 4 :(得分:1)

我遇到了同样的问题...我想验证关联的对象,并让valid?方法返回false,但不添加“多余的”消息,如“帐户无效”。我只希望帐户验证消息显示在帐户字段旁边。

我发现完成此任务的唯一方法是覆盖run_validations!,如下所示。在此示例中,关联为has_many :contacts

def run_validations!
  valid = super
  contacts.each do |contact|
    valid = false unless contact.valid?(validation_context)
  end
  valid
end

不要使用valid &&= contacts.all? ...,因为如果基类已经无效,这将阻止对联系人进行验证,如果其中一个联系人验证失败,将停止迭代。

或许将其概括为一些关注模块,但我只需要一次。

答案 5 :(得分:1)

对于那些仍然在Rails 2上的人,你可以用以下代码覆盖validates_associated:

module ActiveRecord::Validations::ClassMethods
  def validates_associated(association, options = {})
    class_eval do
      validates_each(association) do |record, associate_name, value|
        associate = record.send(associate_name)
        if associate && !associate.valid?
          associate.errors.each do |key, value|
            record.errors.add(key, value)
          end
        end
      end
    end
  end
end

来源:http://pivotallabs.com/alias-method-chain-validates-associated-informative-error-message/

答案 6 :(得分:1)

如果仍然需要,则可以在Rails 5.2上进行以下操作

#app/validators/with_own_error_messages_validator.rb
class WithOwnErrorMessagesValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    Array(value).each do |v|
      unless v.valid?
        v.errors.full_messages.each do |msg|
          record.errors.add(attribute, msg, options.merge(value: value))
        end
      end
    end
  end
end

#app/models/project.rb
class Project < ApplicationRecord
  validates :attachments, with_own_error_messages: true
  has_many :attachments, as: :attachable, validate: false
end

请注意validate: false关联上的has_many。这是必需的,因为Rails现在默认情况下会验证关联。没有它,您会收到Attachment错误消息以及一般的Attachments is invalid

希望这会有所帮助。