This project is archived and is in readonly mode.

#1625 ✓stale
Scott Becker

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

Reported by Scott Becker | December 24th, 2008 @ 01:40 AM | in 3.x

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

}}}

Comments and changes to this ticket

  • Scott Becker

    Scott Becker December 24th, 2008 @ 01:45 AM

    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>
    
  • Adam Milligan

    Adam Milligan December 24th, 2008 @ 03:10 PM

    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?

  • Scott Becker

    Scott Becker December 24th, 2008 @ 08:15 PM

    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.

  • Adam Milligan

    Adam Milligan December 25th, 2008 @ 03:45 PM

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

  • Jeff Cohen

    Jeff Cohen January 5th, 2009 @ 08:16 PM

    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?

  • Scott Becker

    Scott Becker January 5th, 2009 @ 10:22 PM

    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.

  • Scott Becker

    Scott Becker January 6th, 2009 @ 02:10 AM

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

  • Scott Becker

    Scott Becker January 6th, 2009 @ 02:23 AM

    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.

  • Pratik

    Pratik March 7th, 2009 @ 10:57 AM

    • Assigned user set to “Pratik”
  • nbenes

    nbenes April 14th, 2010 @ 07:27 PM

    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

  • Martin Andert

    Martin Andert April 14th, 2010 @ 07:44 PM

    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?

  • Scott Becker

    Scott Becker April 14th, 2010 @ 09:28 PM

    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.

  • Jeremy Kemper

    Jeremy Kemper May 4th, 2010 @ 06:48 PM

    • Milestone changed from 2.x to 3.x
  • Santiago Pastorino

    Santiago Pastorino February 2nd, 2011 @ 05:03 PM

    • 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.

  • Santiago Pastorino

    Santiago Pastorino February 2nd, 2011 @ 05:03 PM

    • State changed from “open” to “stale”

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Referenced by

Pages