Nick KallenNick Kallen
alias_method_chain :validates_associated, :informative_error_message
edit Posted by Nick Kallen on Friday January 04, 2008 at 01:38AM

I dislike the vague error message produced by validates_associated.

class User
  validates_associated :profile
  delegate ..., :to => :profile
end

I see the following error message: profile is invalid. But WHY was the profile invalid? The validation errors from the profile should bubble up to the user. So,

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

Now we see:

Music tastes can't be blank

Eh, voila!

Comments

  1. Joshua Joshua on January 24, 2008 at 03:04PM

    I really like this, but it seems to only work with has_one associations. Here's my adaptation, for better or worse:

    def validates_associated(*associations) associations.each do |association| class_eval do validates_each(associations) do |record, associate_name, value| associates = record.send(associate_name) associates = [associates] unless associates.respond_to?('each') associates.each do |associate| if associate && !associate.valid? associate.errors.each do |key, value| record.errors.add(key, value) end end end end end end end

  2. Joshua Joshua on January 24, 2008 at 03:06PM

    Geeez, that's ugly. Try here: http://pastie.caboo.se/142774

  3. sandro sandro on April 29, 2008 at 12:20AM

    Perfect!

    This was super helpful, thanks for solving such an annoying problem.

  4. fadhli fadhli on May 26, 2008 at 12:12PM

    Hi, thanks for the tips.

    Excuse me for this probably stupid question but where do I put that piece of code?

    Thanks

  5. Nathan Bertram Nathan Bertram on January 02, 2009 at 03:50PM

    Thanks for the solution. Had a problem with duplicated error messages due to the way we were handling nested models. Here's a quick solution to remove those duplicates:

    http://pastie.org/350618

    @fadhli simply throw that code in any .rb file in /config/initializers and it will be automatically run =)

  6. Wolfram Arnold Wolfram Arnold on January 20, 2009 at 04:16AM

    Actually, the code posted by Joshua and Nathan contains one loop too many. This is responsible for the duplication of error messages. Also Nick's code throws away the value (block parameter) and then gets the same thing again by calling record.send(associate_name). That's redundant. With these cleanups, the has_many validation code reduces to:

    http://pastie.org/365402

  7. Johnathan Niziol Johnathan Niziol on January 30, 2009 at 02:56PM

    I have had problems performing a conditional validation when I implement any of these extensions. Has anyone else encountered similar situations?

    I suspect that it expecting the :if to be another attribute to validate.

  8. Johnathan Niziol Johnathan Niziol on February 06, 2009 at 09:23PM

    I found Nathan's worked well, but like I said earlier, doesn't take validates_associated :foo, :if => :bar.

    This one does though:

    http://www.pastie.org/382024