проверяет, связано с сообщением об ошибке модели - PullRequest
26 голосов
/ 12 сентября 2011

У меня есть две модели следующим образом

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 ]

28 голосов
/ 12 сентября 2011

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

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

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

11 голосов
/ 29 апреля 2016

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

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

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

4 голосов
/ 17 февраля 2012

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

<%= render :partial => 'shared/errors', :locals => {:instance => @account.owner} %>
<%= render :partial => 'shared/errors', :locals => {:instance => @account} %>
1 голос
/ 23 октября 2018

Если так или иначе это необходимо, то на 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.

Надеюсь, это поможет.

1 голос
/ 22 марта 2013

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

1 голос
/ 13 марта 2013

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

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

1 голос
/ 12 сентября 2011

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

@user.account.errors

или

@account = @user.build_account
@account.errors

или в виде:

<%= error_messages_for :account %>

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...