views:

236

answers:

3

Can anyone explain why this happens?

mybox:$ ruby script/console
Loading development environment (Rails 2.3.5)
>> foo = Foo.new
=> #<Foo id: nil, customer_id: nil, created_at: nil, updated_at: nil>
>> bar = Bar.new
=> #<Bar id: nil, bundle_id: nil, alias: nil, real: nil, active: true, list_type: 0, body_record_active: false, created_at: nil, updated_at: nil>
>> bar.save
=> false
>> bar.errors.each_full { |msg| puts msg }
Real can't be blank
Real You must supply a valid email
=> ["Real can't be blank", "Real You must supply a valid email"]

So far that is perfect, that is what i want the error message to read. Now for more:

>> foo.bars << bar
=> [#<Bar id: nil, bundle_id: nil, alias: nil, real: nil, active: true, list_type: 0, body_record_active: false, created_at: nil, updated_at: nil>]
>> foo.save
=> false
>> foo.errors.to_xml
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<errors>\n  <error>Bars is invalid</error>\n</errors>\n"

That is what I can't figure out. Why am I getting Bars is invalid versus the error messages displayed above, ["Real can't be blank", "Real you must supply a valid email"] etc.

My controller simply has a respond_to method with the following in it:

 format.xml  { render :xml => @foo.errors, :status => :unprocessable_entity }

How do I have this output the real error messages so the user has some insight into what they did wrong? How do I write my render method in my controller to show all of the appropriate error messages?

A: 

It's because the errors for bar are stored in the bar object. To get these errors you have to do something like this:

foo.bar.each do |bar|
  bar.errors.each_full { |msg| puts msg }
end

It's all convoluted to me, but I haven't figured out the best way to get all the errors in one list (besides handling it my self). I understand the reasoning behind it (as each object should only know about it's own errors). What I usually do is extent ActiveRecord::Errors and create a new each_full_with_associations function that returns them all.

It all makes sense when you see it on a form with nested fields. In that case the errors are shown properly and all is good.

Tony Fontenot
Would I have to write an xml builder template to show those error messages?
randombits
See my edit ...
Tony Fontenot
any chance to see an example of how I'd go about doing that? would love to be able to show all child errors in my xml output.
randombits
+1  A: 

I think you are using

validates_associated :bar in your foo.rb MODEL

so it only giving "Bars is invalid"

to check the error messages for bars either you have to do following in your

VIEW

<%= error_messages_for :foo, :bar %>

Controller

foo.bar.errors.to_xml

& to skip "bar is invalid" message put following method in foo.rb

  def after_validation
    # Skip errors that won't be useful to the end user
    filtered_errors = self.errors.reject{ |err| %w{ bar }.include?(err.first) }
    self.errors.clear
    filtered_errors.each { |err| self.errors.add(*err) }
  end
Salil
I don't think error_messages_for works for xml builder templates.
randombits
A: 

We used to overwrite an errors method in particular model, if we needed errors of child objects too, smth like that

class Foo < ActiveRecord::Base

  alias :errors_without_children :errors

  def errors
    self.bars.each do |i|
      i.errors.each_full do |msg|
        errors_without_children.add_to_base msg
      end
    end
    errors_without_children
  end

end

You can still optimise it more. But this one already adds all bars objects' error messages to foo.

Draco Ater