Проверки, связанные с сообщением об ошибке модели
У меня есть две модели:
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"
Ответы
Ответ 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/