validator validations validates rails method greater_than custom create ruby-on-rails validation

ruby on rails - validations - valida asociado con el mensaje de error del modelo



rails validates if (7)

Me encontré con el mismo problema ... Quiero validar los objetos asociados, y tener el valid? El método devuelve false, pero no agrega un mensaje (superfluo) como ''Cuenta inválida''. Solo quiero que los mensajes de validación de la cuenta aparezcan junto a los campos de la cuenta.

¡La única manera que encontré para lograr esto es anular run_validations! , como abajo. En este ejemplo, la asociación es has_many :contacts :

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

No use valid &&= contacts.all? ... valid &&= contacts.all? ... porque eso evitará la validación en los contactos si la clase base ya no es válida, y detendrá la iteración si uno de los contactos falla en la validación.

Quizás es una idea generalizar esto en algún módulo de Preocupación, pero solo lo necesité una vez.

Tengo dos modelos de la siguiente manera

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

Ahora cuando asocio una cuenta a un usuario dice

"La cuenta no es válida"

En su lugar, quiero obtener el mensaje de error directamente de ese modelo. así que debería decir

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

Hay alguna forma de hacer esto ?

No quiero dar un mensaje genérico como:

validates_associated :account , :message=>"one of the three validations failed"


Para aquellos que aún están en Rails 2, puede sobrescribir validates_associated con el siguiente código:

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

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


Para obtener los mensajes de error para la cuenta, tendría que llamar al método de errors en esa instancia:

@user.account.errors

o

@account = @user.build_account @account.errors

o en la vista:

<%= error_messages_for :account %>

Estoy asumiendo que es una relación has_one.


Puede escribir su propio validador personalizado, basado en el código del validador incorporado.

Al buscar el código fuente de validates_associated, vemos que usa el "AssociatedValidator". El código fuente para eso es:

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

Así que puedes usar esto como un ejemplo para crear un validador personalizado que burbujee mensajes de error como este:

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

Puede poner este código en un inicializador, algo así como /initializers/associated_bubbling_validator.rb .

Finalmente, lo validarías así:

class User < ActiveRecord::Base validates_associated_bubbling :account end

NOTA: el código anterior no se ha probado completamente, pero si no funciona del todo, es de esperar que sea suficiente para ponerlo en el camino correcto


Puede ser que puedes probar algo como se indica a continuación

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

A través de obj[:value] está accediendo al objeto Cuenta validado. Así obj [[valor] .errors le dará errores.


Si así lo necesita, lo siguiente funciona en 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

Tenga en cuenta la validate: false en la asociación has_many . Esto es necesario ya que Rails ahora valida las asociaciones de forma predeterminada. Sin él, obtiene los mensajes de error del Attachment más un Archivo Attachments is invalid genérico Attachments is invalid .

Espero que esto ayude.


Una solución vainilla sería tener una segunda representación de error para el objeto asociado:

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