Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Allow active record errors to_xml to return separate tags for attribute and message

#1625

I needed to return validation errors to an external program via web service so that it could allow a user to fix them.

The standard errors.to_xml method only returns errors as full with underscores converted to spaces, so there is no way for a program to distinguish the attribute name from the error message.

This simple patch adds an :extended option to the to_xml method on the Errors class, which will break out errors into separate "attribute" and "message" tags for easier parsing by external programs. By default this is set to false so existing code continues to work.

Example usage:

{{{ company = Company.create(:address => '123 First St.') company.errors.to_xml(:extended => true)

=> <?xml version="1.0" encoding="UTF-8"?>

name

is too short (minimum is 5 characters)

name

can't be blank

address

can't be blank

}}}

And the existing, standard output, which still works:

{{{ company = Company.create(:address => '123 First St.') company.errors.to_xml

=> <?xml version="1.0" encoding="UTF-8"?>

Name is too short (minimum is 5 characters)

Name can't be blank

Address can't be blank

}}}

Reported by Scott Becker · December 24th, 2008 @ 01:40 AM

State: stale
Milestone: 3.x
Assigned to: Pratik Pratik
Importance: none

Activity

  1. Scott Becker
    Scott Becker

    Those examples didn't format right. Let me try that again.

    Example usage:

    
    company = Company.create(:address => '123 First St.')
    company.errors.to_xml(:extended => true)
    # =>  <?xml version="1.0" encoding="UTF-8"?>
    #     <errors>
    #       <error>
    #         <attribute>name</attribute>
    #         <message>is too short (minimum is 5 characters)</message>
    #       </error>
    #       <error>
    #         <attribute>name</attribute>
    #         <message>can't be blank</message>
    #       </error>
    #       <error>
    #         <attribute>address</attribute>
    #         <message>can't be blank</message>
    #       </error>
    #     </errors>
    

    And the existing, standard output, which still works:

    
    company = Company.create(:address => '123 First St.')
    company.errors.to_xml
    # =>  <?xml version="1.0" encoding="UTF-8"?>
    #     <errors>
    #       <error>Name is too short (minimum is 5 characters)</error>
    #       <error>Name can't be blank</error>
    #       <error>Address can't be blank</error>
    #     </errors>
    

    December 24th, 2008 @ 01:45 AM

  2. Adam Milligan
    Adam Milligan

    In my opinion, "extended" isn't a particularly descriptive option name for this behavior. Something like "include_error_components" or "skip_message_agglomeration" would be more appropriate. I'm sure someone can come up with something less verbose but equally description.

    Also, what is the expected behavior for errors added to base?

    December 24th, 2008 @ 03:10 PM

  3. Scott Becker
    Scott Becker

    Errors added to base would work the same way:

    
    >> d = Dataset.new
    => #<Dataset id: nil, ...>
    >> d.errors.add_to_base("is invalid")
    => ["is invalid"]
    >> puts d.errors.to_xml(:extended => true)
    <?xml version="1.0" encoding="UTF-8"?>
    <errors>
      <error>
        <attribute>base</attribute>
        <message>is invalid</message>
      </error>
    </errors>
    

    I think that is appropriate, it's how it works with to_json as well.

    
    d.errors.to_json
    
    
    [["base", "is invalid"]]
    

    In my opinion, it should be broken out by default with XML as well, since its intended to be parsed by other programs. But since it worked the other way be default before, I felt it should continue to work that way so as not to break other programs depending on that behavior.

    I don't care what the option is called, but "extended" was the least verbose, yet still descriptive thing I came up with.

    December 24th, 2008 @ 08:15 PM

  4. Adam Milligan
    Adam Milligan

    I should have been more clear. When I wrote "what is the expected behavior for" I meant "there is no test for."

    December 25th, 2008 @ 03:45 PM

  5. Jeff Cohen
    Jeff Cohen

    I like this idea. However, I might suggest that the content be the same as it was before in the field. For example, instead of:

    
      <attribute>name</attribute>
      <message>is too short (minimum is 5 characters)</message>
    

    I think it should be:

    
      <attribute>name</attribute>
      <message>Name is too short (minimum is 5 characters)</message>
    

    What do you think?

    January 5th, 2009 @ 08:16 PM

  6. Scott Becker
    Scott Becker

    Adam Milligan -

    I will add another patch including tests verifying the expected behavior for serializing errors added to base later today.

    Jeff Cohen -

    That would make it function differently than JSON serialization, which is more flexible, in my opinion. Let me explain:

    
    company = Company.new
    company.errors.add("name", "is invalid")
    company.errors.to_json
    
    # => [["name", "is invalid"]]
    

    As you can see, with "to_json", the attribute and message are broken out separately and not repeated.

    I think that the XML errors serialization should have the ability to work the same way. If I want to include the name in the message, I can add that back in later. If its already included in the message, there is no way to easy way to remove it if it has been humanized - with underscores converted to spaces. This can become an issue if you want the message by itself, or if your form field label differs from the database field name.

    January 5th, 2009 @ 10:22 PM

  7. Scott Becker
    Scott Becker

    Here is a new patch adding additional tests verifying the expected behavior for serializing errors added to base, as per Adam Milligan's suggestion.

    January 6th, 2009 @ 02:10 AM

  8. Scott Becker
    Scott Becker

    Oops, my name and email weren't set correctly in the second commit of that last patch. Here's an updated one with correct contact info.

    January 6th, 2009 @ 02:23 AM

  9. Pratik
    Pratik
    • Assigned user set to Pratik

    March 7th, 2009 @ 10:57 AM

  10. nbenes
    nbenes

    Whatever happened to this ticket/issue? I don't see an update and the behavior in ActiveRecord still looks to be the same. It really should be specifying which fields the errors occurred on when you call errors.to_xml

    April 14th, 2010 @ 07:27 PM

  11. Martin Andert
    Martin Andert

    I would prefer it this way:

    <errors>
      <error on="title">Title can't be blank</error>
      <error on="username">Username is already taken</error>
    </errors>
    

    So only an XML attribute ("on") is added for the Error attribute, which is backwards compatible.

    Cool would also be some parsable information for the "type" of error, so the consumer of the returned XML would be able to replace the full message with a custom (eg. localized) one:

    <errors>
      <error on="title" type="blank">Title can't be blank</error>
      <error on="username" type="taken">Username is already taken</error>
      <error on="username" type="invalid">Username has an invalid format</error>
      <error on="password" type="too_short">Password is too short (at least 6 characters)</error>
    </errors>
    

    I have already monkey-patched the Error class in one of my apps to produce such output. Anyone interested?

    April 14th, 2010 @ 07:44 PM

  12. Scott Becker
    Scott Becker

    I still think the originally proposed format with the field name and message broken out provides the best flexibility, and maps one-to-one with the JSON error output. If the name is included in the message, there is no way to easy programmatic way to remove it, since it has been humanized with underscores converted to spaces. This is an issue if you want the message by itself, or if your form field label differs from the database field name.

    <errors>
      <error>
        <attribute>name</attribute>
        <message>is too short (minimum is 5 characters)</message>
      </error>
      <error>
        <attribute>name</attribute>
        <message>can't be blank</message>
      </error>
    <errors>
    

    vs JSON:

    [
      ["name", "is too short (minimum is 5 characters)"],
      ["name", "can't be blank"]
    ]
    

    +1 on this. I would love to see this committed within the Rails 3.0 release timeframe.

    April 14th, 2010 @ 09:28 PM

  13. Jeremy Kemper
    Jeremy Kemper
    • Milestone changed from 2.x to 3.x

    May 4th, 2010 @ 06:48 PM

  14. Santiago Pastorino
    Santiago Pastorino
    • State changed from new to open
    • Importance changed from to

    This issue has been automatically marked as stale because it has not been commented on for at least three months.

    The resources of the Rails core team are limited, and so we are asking for your help. If you can still reproduce this error on the 3-0-stable branch or on master, please reply with all of the information you have about it and add "[state:open]" to your comment. This will reopen the ticket for review. Likewise, if you feel that this is a very important feature for Rails to include, please reply with your explanation so we can consider it.

    Thank you for all your contributions, and we hope you will understand this step to focus our efforts where they are most helpful.

    February 2nd, 2011 @ 05:03 PM

  15. Santiago Pastorino
    Santiago Pastorino
    • State changed from open to stale

    February 2nd, 2011 @ 05:03 PM