3

I am using the validates_associated in a model to use the other model's validation code. The problem with this is the message for a failed validation is "..is invalid".

I want to bubble the actual descriptive error form the model validation's failure to the top!

I found this question: validates associated with model's error message

Which had what looks like a very close solution:

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

However it actually hits an error:

undefined method `valid?' for #<TicketType::ActiveRecord_Associations_CollectionProxy:0x007ff86474a478>

Can anybody please help complete this almost working work around!?

The complete error trace is:

undefined method `valid?' for #<TicketType::ActiveRecord_Associations_CollectionProxy:0x007ff8646ba148>

Extracted source (around line #6):
4
5
6
7
8
9

      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

Rails.root: /Users/andyarmstrong/Documents/Personal/clazzoo_main

Application Trace | Framework Trace | Full Trace
config/initializers/associated_bubbling_validator.rb:6:in `block in validate_each'
config/initializers/associated_bubbling_validator.rb:5:in `each'
config/initializers/associated_bubbling_validator.rb:5:in `validate_each'
app/controllers/events_controller.rb:158:in `block in create'
Community
  • 1
  • 1
RenegadeAndy
  • 5,440
  • 18
  • 70
  • 130

1 Answers1

8

value is actually not an Array, but an ActiveRecord::Associations::CollectionProxy.

So...

value.is_a?(Array) ? value : [value] #=> [value]

and

[value].each do |v|
  unless v.valid?
    # ......
  end
end

would raise that error

undefined method `valid?' for #<TicketType::ActiveRecord_Associations_CollectionProxy:0x007ff86474a478>

You can try this:

module ActiveRecord
  module Validations
    class AssociatedBubblingValidator < ActiveModel::EachValidator
      def validate_each(record, attribute, value)
        ((value.kind_of?(Enumerable) || value.kind_of?(ActiveRecord::Relation)) ? 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
scorix
  • 2,436
  • 19
  • 23