Better validates_associated method for Rails 3?

后端 未结 4 738
猫巷女王i
猫巷女王i 2021-02-04 03:47

Rails 3 includes the validates_associated which is automatically called when saving a nested model. The problem with the method is the message is terrible - \"Mode

4条回答
  •  情书的邮戳
    2021-02-04 04:32

    I was having this problem, and in the end I used the solution given here by Ben Lee:

    validates associated with model's error message

    Ben says:

    You can write your own custom validator, based on the code for the built-in validator.

    Looking up the source code for validates_associated, we see that it uses the "AssociatedValidator". The source code for that is:

    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
    

    So you can use this as an example to create a custom validator that bubbles error messages like this:

    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
    

    You can put this code in an initializer, something like /initializers/associated_bubbling_validator.rb.

    Finally, you'd validate like so:

    class User < ActiveRecord::Base
     validates_associated_bubbling :account
    end
    

    NOTE: the above code is completely untested, but if it doesn't work outright, it is hopefully enough to put you on the right track

提交回复
热议问题