Подтвердить что ты не робот

Проверки, связанные с сообщением об ошибке модели

У меня есть две модели:

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"
4b9b3361

Ответ 1

Вы можете написать свой собственный валидатор, основанный на коде для встроенного валидатора.

Поднимая исходный код для 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

ПРИМЕЧАНИЕ: вышеуказанный код полностью не протестирован, но если он не работает напрямую, мы надеемся достаточно, чтобы поставить вас на правильный трек

Ответ 2

Ванильным решением было бы иметь второй рендеринг ошибок для связанного объекта:

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

Ответ 3

Может быть, вы можете попробовать что-то, как указано ниже

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

Через obj[:value] вы получаете доступ к проверяемому объекту Account. Таким образом, obj [: value].errors выдаст вам ошибки.

Ответ 4

Чтобы получить сообщения об ошибках для учетной записи, вам нужно вызвать метод errors в этом экземпляре:

@user.account.errors

или

@account = @user.build_account
@account.errors

или в представлении:

<%= error_messages_for :account %>

Я делаю предположение, что это отношение has_one.

Ответ 5

Я столкнулся с той же проблемой... Я хочу проверить связанные объекты и метод 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? ..., потому что это предотвратит проверку контактов, если базовый класс уже недействителен, и остановит итерацию, если один из контактов не прошел проверку.

Возможно, это идея обобщить это на некоторый модуль Концерна, но мне это нужно было только один раз.

Ответ 6

Для тех, кто еще находится на 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/