<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -28,7 +28,7 @@ Object.extend(Jester.Resource, {
     new_model = eval(model + &quot; = &quot; + Jester.Constructor(model));
     new_model.prototype = new Jester.Resource();
     Object.extend(new_model, Jester.Resource);
-    
+
     // We delay instantiating XML.ObjTree() so that it can be listed at the end of this file instead of the beginning
     if (!Jester.Tree) {
       Jester.Tree = new XML.ObjTree();
@@ -47,20 +47,20 @@ Object.extend(Jester.Resource, {
     options.singular_xml = options.singular.replace(/_/g, &quot;-&quot;);
     options.plural_xml   = options.plural.replace(/_/g, &quot;-&quot;);
     options.remote       = false;
-    
+
     // Establish prefix
     var default_prefix = window.location.protocol + &quot;//&quot; + window.location.hostname + (window.location.port ? &quot;:&quot; + window.location.port : &quot;&quot;);
     if (options.prefix &amp;&amp; options.prefix.match(/^https?:/))
       options.remote = true;
-      
+
     if (!options.prefix)
       options.prefix = default_prefix;
-    
+
     if (!options.prefix.match(/^(https?|file):/))
       options.prefix = default_prefix + (options.prefix.match(/^\//) ? &quot;&quot; : &quot;/&quot;) + options.prefix;
-            
+
     options.prefix = options.prefix.replace(/\b\/+$/,&quot;&quot;);
-    
+
     // Establish custom URLs
     options.urls = Object.extend(this._default_urls(options), options.urls);
 
@@ -69,11 +69,11 @@ Object.extend(Jester.Resource, {
     new_model.options = options;
     for(var opt in options)
       new_model[&quot;_&quot; + opt] = options[opt];
-    
+
     // Establish custom URL helpers
     for (var url in options.urls)
       eval('new_model._' + url + '_url = function(params) {return this._url_for(&quot;' + url + '&quot;, params);}');
-    
+
     if (options.checkNew)
       this.buildAttributes(new_model, options);
 
@@ -82,14 +82,14 @@ Object.extend(Jester.Resource, {
 
     return new_model;
   },
-  
+
   buildAttributes: function(model, options) {
     model = model || this;
     var async = options.asynchronous;
-    
+
     if (async == null)
       async = true;
-    
+
     var buildWork = bind(model, function(doc) {
       if (this._format == &quot;json&quot;)
         this._attributes = this._attributesFromJSON(doc);
@@ -98,7 +98,7 @@ Object.extend(Jester.Resource, {
     });
     model.requestAndParse(options.format, buildWork, model._new_url(), {asynchronous: async});
   },
-  
+
   loadRemoteJSON : function(url, callback, user_callback) {
     // tack on user_callback if there is one, and only if it's really a function
     if (typeof(user_callback) == &quot;function&quot;)
@@ -108,21 +108,21 @@ Object.extend(Jester.Resource, {
 
     var script = document.createElement(&quot;script&quot;);
     script.type = &quot;text/javascript&quot;;
-    
+
     if (url.indexOf(&quot;?&quot;) == -1)
       url += &quot;?&quot;;
     else
       url += &quot;&amp;&quot;;
     url += &quot;callback=jesterCallback&quot;;
     script.src = url;
-    
+
     document.firstChild.appendChild(script);
   },
 
   requestAndParse : function(format, callback, url, options, user_callback, remote) {
     if (remote &amp;&amp; format == &quot;json&quot; &amp;&amp; user_callback)
       return this.loadRemoteJSON(url, callback, user_callback)
-    
+
     parse_and_callback = null;
     if (format.toLowerCase() == &quot;json&quot;) {
       parse_and_callback = function(transport) {
@@ -158,7 +158,7 @@ Object.extend(Jester.Resource, {
     }
     else
       user_callback = function(arg){return arg;}
-    
+
     if (options.asynchronous) {
       options.onComplete = function(transport, json) {user_callback(callback(transport), json);}
       return new Ajax.Request(url, options).transport;
@@ -176,12 +176,12 @@ Object.extend(Jester.Resource, {
       callback = params;
       params = null;
     }
-    
+
     var findAllWork = bind(this, function(doc) {
       if (!doc) return null;
-      
+
       var collection = this._loadCollection(doc);
-      
+
       if (!collection) return null;
 
       // This is better than requiring the controller to support a &quot;limit&quot; parameter
@@ -193,9 +193,9 @@ Object.extend(Jester.Resource, {
 
     var findOneWork = bind(this, function(doc) {
       if (!doc) return null;
-      
+
       var base = this._loadSingle(doc);
-      
+
       // if there were no properties, it was probably not actually loaded
       if (!base || base._properties.length == 0) return null;
 
@@ -213,23 +213,23 @@ Object.extend(Jester.Resource, {
       if (isNaN(parseInt(id))) return null;
       if (!params) params = {};
       params.id = id;
-      
+
       var url = this._show_url(params);
       return this.requestAndParse(this._format, findOneWork, url, {}, callback, this._remote);
     }
   },
-  
+
   build : function(attributes) {
     return new this(attributes);
   },
-  
+
   create : function(attributes, callback) {
     var base = new this(attributes);
-    
+
     createWork = bind(this, function(saved) {
       return callback(base);
     });
-    
+
     if (callback) {
       return base.save(createWork);
     }
@@ -238,9 +238,13 @@ Object.extend(Jester.Resource, {
       return base;
     }
   },
-  
-  // If not given an ID, destroys itself, if it has an ID.  If given an ID, destroys that record.
-  // You can call destroy(), destroy(1), destroy(callback()), or destroy(1, callback()), and it works as you expect.
+
+  // Destroys a REST object.  Can be used as follows:
+  // object.destroy() - when called on an instance of a model, destroys that instance
+  // Model.destroy(1) - destroys the Model object with ID 1
+  // Model.destroy({parent: 3, id: 1}) - destroys the Model object with Parent ID 3 and ID 1
+  //
+  // Any of these forms can also be passed a callback function as an additional parameter and it works as you expect.
   destroy : function(params, callback) {
     if (typeof(params) == &quot;function&quot;) {
       callback = params;
@@ -251,7 +255,7 @@ Object.extend(Jester.Resource, {
     }
     params.id = params.id || this.id;
     if (!params.id) return false;
-    
+
     var destroyWork = bind(this, function(transport) {
       if (transport.status == 200) {
         if (!params.id || this.id == params.id)
@@ -261,13 +265,13 @@ Object.extend(Jester.Resource, {
       else
         return false;
     });
-    
+
     return this.request(destroyWork, this._destroy_url(params), {method: &quot;delete&quot;}, callback);
   },
-  
+
   _interpolate: function(string, params) {
     if (!params) return string;
-    
+
     var result = string;
     params.each(function(pair) {
       var re = new RegExp(&quot;:&quot; + pair.key, &quot;g&quot;);
@@ -278,18 +282,18 @@ Object.extend(Jester.Resource, {
     });
     return result;
   },
-  
+
   _url_for : function(action, params) {
     if (!this._urls[action]) return &quot;&quot;;
     // if an integer is sent, it's assumed just the ID is a parameter
     if (typeof(params) == &quot;number&quot;) params = {id: params}
-    
+
     if (params) params = $H(params);
-    
+
     var url = this._interpolate(this._prefix + this._urls[action], params)
     return url + (params &amp;&amp; params.any() ? &quot;?&quot; + params.toQueryString() : &quot;&quot;);
   },
-  
+
   _default_urls : function(options) {
     urls = {
       'show' : &quot;/&quot; + options.plural + &quot;/:id.&quot; + options.format,
@@ -298,17 +302,17 @@ Object.extend(Jester.Resource, {
     }
     urls.create = urls.list;
     urls.destroy = urls.update = urls.show;
-    
+
     return urls;
   },
-  
+
   // Converts a JSON hash returns from ActiveRecord::Base#to_json into a hash of attribute values
   // Does not handle associations, as AR's #to_json doesn't either
   // Also, JSON doesn't include room to store types, so little auto-transforming is done here (just on 'id')
   _attributesFromJSON : function(json) {
     if (!json || json.constructor != Object) return false;
     if (json.attributes) json = json.attributes;
-    
+
     var attributes = {};
     var i = 0;
     for (var attr in json) {
@@ -323,10 +327,10 @@ Object.extend(Jester.Resource, {
       i += 1;
     }
     if (i == 0) return false; // empty hashes should just return false
-    
+
     return attributes;
   },
-  
+
   // Converts the XML tree returned from a single object into a hash of attribute values
   _attributesFromTree : function(elements) {
     var attributes = {}
@@ -339,10 +343,10 @@ Object.extend(Jester.Resource, {
         else
           value = undefined;
       }
-      
+
       // handle empty value (pass it through)
       if (!value) {}
-      
+
       // handle scalars
       else if (typeof(value) == &quot;string&quot;) {
         // perform any useful type transformations
@@ -360,7 +364,7 @@ Object.extend(Jester.Resource, {
       // handle arrays (associations)
       else {
         var relation = value; // rename for clarity in the context of an association
-        
+
         // first, detect if it's has_one/belongs_to, or has_many
         var i = 0;
         var singular = null;
@@ -370,17 +374,17 @@ Object.extend(Jester.Resource, {
             singular = val;
           i += 1;
         }
-        
+
         // has_many
         if (relation[singular] &amp;&amp; typeof(relation[singular]) == &quot;object&quot; &amp;&amp; i == 1) {
           var value = [];
           var plural = attr;
           var name = singular.camelize().capitalize();
-          
+
           // force array
           if (!(elements[plural][singular].length &gt; 0))
             elements[plural][singular] = [elements[plural][singular]];
-          
+
           elements[plural][singular].each( bind(this, function(single) {
             // if the association hasn't been modeled, do a default modeling here
             // hosted object's prefix and format are inherited, singular and plural are set
@@ -396,7 +400,7 @@ Object.extend(Jester.Resource, {
         else {
           singular = attr;
           var name = singular.capitalize();
-          
+
           // if the association hasn't been modeled, do a default modeling here
           // hosted object's prefix and format are inherited, singular is set from the XML
           if (eval(&quot;typeof(&quot; + name + &quot;)&quot;) == &quot;undefined&quot;) {
@@ -405,25 +409,25 @@ Object.extend(Jester.Resource, {
           value = eval(name + &quot;.build(this._attributesFromTree(value))&quot;);
         }
       }
-      
+
       // transform attribute name if needed
       attribute = attr.replace(/-/g, &quot;_&quot;);
       attributes[attribute] = value;
     }
-    
+
     return attributes;
   },
-  
+
   _loadSingle : function(doc) {
     var attributes;
     if (this._format == &quot;json&quot;)
       attributes = this._attributesFromJSON(doc);
     else
       attributes = this._attributesFromTree(doc[this._singular_xml]);
-    
+
     return this.build(attributes);
   },
-  
+
   _loadCollection : function(doc) {
     var collection;
     if (this._format == &quot;json&quot;) {
@@ -435,14 +439,14 @@ Object.extend(Jester.Resource, {
       // if only one result, wrap it in an array
       if (!Jester.Resource.elementHasMany(doc[this._plural_xml]))
         doc[this._plural_xml][this._singular_xml] = [doc[this._plural_xml][this._singular_xml]];
-      
+
       collection = doc[this._plural_xml][this._singular_xml].map( bind(this, function(elem) {
         return this.build(this._attributesFromTree(elem));
       }));
     }
     return collection;
   }
-  
+
 });
 
 Object.extend(Jester.Resource.prototype, {
@@ -450,32 +454,32 @@ Object.extend(Jester.Resource.prototype, {
     // Initialize no attributes, no associations
     this._properties = [];
     this._associations = [];
-    
+
     this.setAttributes(this.klass._attributes || {});
     this.setAttributes(attributes);
 
     // Initialize with no errors
     this.errors = [];
-    
+
     // Establish custom URL helpers
     for (var url in this.klass._urls)
       eval('this._' + url + '_url = function(params) {return this._url_for(&quot;' + url + '&quot;, params);}');
   },
   after_initialization: function(){},
-  
+
   new_record : function() {return !(this.id);},
   valid : function() {return ! this.errors.any();},
-  
+
   reload : function(callback) {
     var reloadWork = bind(this, function(copy) {
       this._resetAttributes(copy.attributes(true));
-  
+
       if (callback)
         return callback(this);
       else
         return this;
     });
-    
+
     if (this.id) {
       if (callback)
         return this.klass.find(this.id, {}, reloadWork);
@@ -485,7 +489,7 @@ Object.extend(Jester.Resource.prototype, {
     else
       return this;
   },
-  
+
   // If not given an ID, destroys itself, if it has an ID.  If given an ID, destroys that record.
   // You can call destroy(), destroy(1), destroy(callback()), or destroy(1, callback()), and it works as you expect.
   destroy : function(given_id, callback) {
@@ -495,7 +499,7 @@ Object.extend(Jester.Resource.prototype, {
     }
     var id = given_id || this.id;
     if (!id) return false;
-    
+
     var destroyWork = bind(this, function(transport) {
       if (transport.status == 200) {
         if (!given_id || this.id == given_id)
@@ -505,10 +509,10 @@ Object.extend(Jester.Resource.prototype, {
       else
         return false;
     });
-    
+
     return this.klass.request(destroyWork, this._destroy_url(), {method: &quot;delete&quot;}, callback);
   },
-  
+
   save : function(callback) {
     var saveWork = bind(this, function(transport) {
       var saved = false;
@@ -544,13 +548,13 @@ Object.extend(Jester.Resource.prototype, {
 
       return (transport.status &gt;= 200 &amp;&amp; transport.status &lt; 300 &amp;&amp; this.errors.length == 0);
     });
-  
+
     // reset errors
     this._setErrors([]);
-  
+
     var url = null;
     var method = null;
-    
+
     // collect params
     var params = {};
     var urlParams = {};
@@ -558,7 +562,7 @@ Object.extend(Jester.Resource.prototype, {
       params[this.klass._singular + &quot;[&quot; + value + &quot;]&quot;] = this[value];
       urlParams[value] = this[value];
     }));
-    
+
     // distinguish between create and update
     if (this.new_record()) {
       url = this._create_url(urlParams);
@@ -569,23 +573,23 @@ Object.extend(Jester.Resource.prototype, {
       method = &quot;put&quot;;
     }
 
-    
+
     // send the request
     return this.klass.request(saveWork, url, {parameters: params, method: method}, callback);
   },
-  
+
   setAttributes : function(attributes)
   {
     $H(attributes).each(bind(this, function(attr){ this._setAttribute(attr.key, attr.value) }));
     return attributes;
   },
-  
+
   updateAttributes : function(attributes, callback)
   {
     this.setAttributes(attributes);
     return this.save(callback);
   },
-  
+
   // mimics ActiveRecord's behavior of omitting associations, but keeping foreign keys
   attributes : function(include_associations) {
     var attributes = {}
@@ -597,28 +601,28 @@ Object.extend(Jester.Resource.prototype, {
     }
     return attributes;
   },
-    
+
   /*
     Internal methods.
   */
-  
+
   _attributesFromJSON: function()
   {
     return this.klass._attributesFromJSON.apply(this.klass, arguments);
   },
-  
+
   _attributesFromTree: function()
   {
     return this.klass._attributesFromTree.apply(this.klass, arguments);
   },
-  
+
   _errorsFrom : function(raw) {
     if (this.klass._format == &quot;json&quot;)
       return this._errorsFromJSON(raw);
     else
       return this._errorsFromXML(raw);
   },
-  
+
     // Pulls errors from JSON
   _errorsFromJSON : function(json) {
     try {
@@ -626,14 +630,14 @@ Object.extend(Jester.Resource.prototype, {
     } catch(e) {
       return false;
     }
-    
+
     if (!(json &amp;&amp; json.constructor == Array &amp;&amp; json[0] &amp;&amp; json[0].constructor == Array)) return false;
-    
+
     return json.map(function(pair) {
       return pair[0].capitalize() + &quot; &quot; + pair[1];
     });
   },
-  
+
   // Pulls errors from XML
   _errorsFromXML : function(xml) {
     if (!xml) return false;
@@ -643,22 +647,22 @@ Object.extend(Jester.Resource.prototype, {
       var errors = [];
       if (typeof(doc.errors.error) == &quot;string&quot;)
         doc.errors.error = [doc.errors.error];
-      
+
       doc.errors.error.each(function(value, index) {
         errors.push(value);
       });
-      
+
       return errors;
     }
     else return false;
   },
-  
+
   // Sets errors with an array.  Could be extended at some point to include breaking error messages into pairs (attribute, msg).
   _setErrors : function(errors) {
     this.errors = errors;
   },
-  
-  
+
+
   // Sets all attributes and associations at once
   // Deciding between the two on whether the attribute is a complex object or a scalar
   _resetAttributes : function(attributes) {
@@ -666,64 +670,64 @@ Object.extend(Jester.Resource.prototype, {
     for (var attr in attributes)
       this._setAttribute(attr, attributes[attr]);
   },
-  
+
   _setAttribute : function(attribute, value) {
     if (value &amp;&amp; typeof(value) == &quot;object&quot; &amp;&amp; value.constructor != Date)
       this._setAssociation(attribute, value);
     else
       this._setProperty(attribute, value);
   },
-  
+
   _setProperties : function(properties) {
     this._clearProperties();
     for (var prop in properties)
       this._setProperty(prop, properties[prop])
   },
-  
+
   _setAssociations : function(associations) {
     this._clearAssociations();
     for (var assoc in associations)
       this._setAssociation(assoc, associations[assoc])
   },
-      
-  _setProperty : function(property, value) {  
+
+  _setProperty : function(property, value) {
     this[property] = value;
     if (!(this._properties.include(property)))
-      this._properties.push(property);  
+      this._properties.push(property);
   },
-  
+
   _setAssociation : function(association, value) {
     this[association] = value;
     if (!(this._associations.include(association)))
       this._associations.push(association);
   },
-  
+
   _clear : function() {
     this._clearProperties();
     this._clearAssociations();
   },
-  
+
   _clearProperties : function() {
     for (var i=0; i&lt;this._properties.length; i++)
       this[this._properties[i]] = null;
     this._properties = [];
   },
-  
+
   _clearAssociations : function() {
     for (var i=0; i&lt;this._associations.length; i++)
       this[this._associations[i]] = null;
     this._associations = [];
   },
-  
+
   // helper URLs
   _url_for : function(action, params) {
     if (!params) params = this.id;
     if (typeof(params) == &quot;object&quot; &amp;&amp; !params.id)
       params.id = this.id;
-    
+
     return this.klass._url_for(action, params);
   }
-  
+
 });
 
 // Returns true if the element has more objects beneath it, or just 1 or more attributes.
@@ -738,7 +742,7 @@ Jester.Resource.elementHasMany = function(element) {
       singular = val;
     i += 1;
   }
-  
+
   return (element[singular] &amp;&amp; typeof(element[singular]) == &quot;object&quot; &amp;&amp; element[singular].length != null &amp;&amp; i == 1);
 }
 
@@ -761,7 +765,7 @@ if(typeof(Resource) == &quot;undefined&quot;)
 
 
 
-/* 
+/*
   Inflector library, contributed graciously to Jester by Ryan Schuft.
   The library in full is a complete port of Rails' Inflector, though Jester only uses its pluralization.
   Its home page can be found at: http://code.google.com/p/inflection-js/</diff>
      <filename>jester.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@
 
 &lt;html&gt;
   &lt;head&gt;
-    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;  
+    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;
     &lt;title&gt;jester.js&lt;/title&gt;
     &lt;script language=&quot;JavaScript&quot; type=&quot;text/javascript&quot; src=&quot;jsunit/app/jsUnitCore.js&quot;&gt;&lt;/script&gt;
     &lt;script language=&quot;JavaScript&quot; type=&quot;text/javascript&quot; src=&quot;../prototype.js&quot;&gt;&lt;/script&gt;
@@ -16,7 +16,7 @@
 
 function setUp () {
   default_prefix = function() {return window.location.protocol + &quot;//&quot; + window.location.hostname + (window.location.port ? &quot;:&quot; + window.location.port : &quot;&quot;);}
-  
+
   ericXML = '&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;user&gt;&lt;created-at type=&quot;datetime&quot;&gt;2007-04-08T15:12:06-04:00&lt;/created-at&gt;&lt;id type=&quot;integer&quot;&gt;1&lt;/id&gt;&lt;first-name&gt;eric&lt;/first-name&gt;&lt;admin type=&quot;boolean&quot;&gt;true&lt;/admin&gt;&lt;/user&gt;'
   camelCaseXML = '&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;cool-thing&gt;&lt;created-at type=&quot;datetime&quot;&gt;2007-04-08T15:12:06-04:00&lt;/created-at&gt;&lt;id type=&quot;integer&quot;&gt;1&lt;/id&gt;&lt;first-name&gt;eric&lt;/first-name&gt;&lt;admin type=&quot;boolean&quot;&gt;true&lt;/admin&gt;&lt;/cool-thing&gt;'
   ericJSON = '{attributes: {id: &quot;1&quot;, first_name: &quot;eric&quot;, admin: &quot;1&quot;, created_at: &quot;2007-04-08 15:12:06&quot;}}'
@@ -32,7 +32,7 @@ function setUp () {
     'first-name' : 'eric',
     'admin' : { '@type' : 'boolean', '#text' : 'true' },
     'created_at' : { '@type' : 'datetime', '#text' : '2007-04-08T15:12:06-04:00' },
-    'posts' : { 
+    'posts' : {
       'post' : [postDetails1, postDetails2]
     }
   }
@@ -41,7 +41,7 @@ function setUp () {
     'first-name' : 'john',
     'admin' : { '@type' : 'boolean', '#text' : 'false' },
     'created_at' : { '@type' : 'datetime', '#text' : '2007-04-09T15:12:06-04:00' },
-    'posts' : { 
+    'posts' : {
       'post' : postDetails3
     }
   }
@@ -51,19 +51,19 @@ function setUp () {
     'admin' : { '@type' : 'boolean', '#text' : 'true' },
     'created_at' : { '@type' : 'datetime', '#text' : '2007-04-10T15:12:06-04:00' }
   }
-  
+
   allUsersDetails = {
     'users' : {
       'user' : [ericDetails, johnDetails, chadDetails]
     }
   }
-  
+
   allPostsDetails = {
     'posts' : {
       'post' : [postDetails1, postDetails2, postDetails3]
     }
   }
-  
+
   // Chad with ID 1, for testing remote site support
   remoteChad = {
     'id' : { '@type' : 'integer', '#text' : '1' },
@@ -71,29 +71,29 @@ function setUp () {
     'admin' : { '@type' : 'boolean', '#text' : 'true' },
     'created_at' : { '@type' : 'datetime', '#text' : '2007-04-10T15:12:06-04:00' }
   }
-  
+
   // test for belongs_to, separate from normal universe
-  postIncludeDetails = { 
+  postIncludeDetails = {
     'id' : { '@type' : 'integer', '#text' : '3' },
-    'title' : 'another title', 
+    'title' : 'another title',
     'body' : 'another body',
     'user' : ericDetails
   }
-  
+
   // test for finding all, but where ObjTree doesn't use an array because there is only one result
   allWithOneUserDetails = {
     'users' : {
       'user' : ericDetails
     }
   }
-  
+
   newUserDetails = {
     'first-name' : undefined,
     'admin' : { '@type' : 'boolean', '#text' : 'false' },
     'created_at' : { '@type' : 'datetime' }
   }
   newUserJSON = '{attributes: {first_name: null, admin: null, created_at: null}}'
-  
+
   Resource.requestAndParse = function (format, callback, url, options, user_callback, remote) {
     if (remote &amp;&amp; format == &quot;json&quot;) {
       jesterCallback = function(json){
@@ -106,15 +106,15 @@ function setUp () {
       eval('var result = ' + Internet[url]);
       return result;
     }
-  
+
     var result = Internet[url];
 
     if (format == &quot;json&quot;)
       eval('result = ' + result);
-      
+
     if (callback)
       result = callback(result);
-      
+
     if (user_callback) {
       changed = true;
       if (typeof(user_callback) == &quot;function&quot;)
@@ -125,42 +125,42 @@ function setUp () {
           result = user_callback(result);
       }
     }
-    
+
     return result;
   }
-  
+
   // JSON callback
   jesterCallback = null;
-  
+
   // mock out the Internet
   Internet = {}
-  
+
   // Remote models
   Resource.model(&quot;User&quot;, {prefix: &quot;http://www.thoughtbot.com&quot;, format: &quot;json&quot;})
   Resource.model(&quot;Post&quot;, {prefix: &quot;http://www.thoughtbot.com&quot;, format: &quot;json&quot;})
-  
+
   Internet[User._show_url(1)] = &quot;jesterCallback(&quot; + ericJSON + &quot;);&quot;;
   Internet[Post._show_url(1)] = &quot;jesterCallback(&quot; + postJSON + &quot;);&quot;;
   Internet[User._list_url()] = &quot;jesterCallback(&quot; + usersJSON + &quot;);&quot;;
-  
+
   // JSON models
   Resource.model(&quot;User&quot;, {format: &quot;json&quot;})
   Resource.model(&quot;Post&quot;, {format: &quot;json&quot;})
-  
+
   Internet[User._show_url(1)] = ericJSON;
   Internet[Post._show_url(1)] = postJSON;
   Internet[User._list_url()] = usersJSON;
   Internet[User._new_url()] = newUserJSON;
-  
+
   // Path prefixed models
   Resource.model(&quot;Post&quot;, {prefix: &quot;/users/:user_id&quot;})
-  
+
   Internet[Post._show_url({id: 1, user_id: 1})] = {'post': postDetails1};
-  
+
   // XML models
   Resource.model(&quot;User&quot;)
   Resource.model(&quot;Post&quot;)
-  
+
   Internet[User._show_url(1)] = {'user': ericDetails};
   Internet[User._show_url(2)] = {'user': johnDetails};
   Internet[User._show_url(3)] = {'user': chadDetails};
@@ -178,7 +178,7 @@ function setUp () {
   // used to make sure callbacks get called
   changed = false;
   assert_changed = function() {assert(changed); changed = false;}
-  
+
   return true;
 }
 
@@ -189,7 +189,7 @@ function setUp () {
 
 function testFind() {
   var eric = User.find(1);
-  
+
   assertEquals(&quot;Attributes should be filled in correctly on find().&quot;, 'eric', eric.first_name);
   assert(&quot;Boolean attributes should be auto-transformed (when format is XML).&quot;, eric.admin);
   assertEquals(&quot;Date attributes should be auto-transformed (when format is XML).&quot;, Date, eric.created_at.constructor);
@@ -201,59 +201,59 @@ function testFind() {
   assertEquals(&quot;Eric's post's body wasn't loaded.&quot;, 'the body', eric.posts[0].body);
   assertEquals(&quot;Eric's second post's title wasn't loaded.&quot;, 'another title', eric.posts[1].title);
   assertEquals(&quot;Eric's second post's body wasn't loaded.&quot;, 'another body', eric.posts[1].body);
-  
+
   // failed find
   var eric = User.find(50);
   assert(eric == null);
-  
+
   // with params
   var ericLite = User.find(1, {lite: true});
   assertEquals(&quot;eric&quot;, ericLite.first_name);
   assertEquals(1, ericLite.id); // make sure ID gets autoset
   assertEquals(2, ericLite._properties.length);
   assert(typeof(ericLite.admin) == &quot;undefined&quot;);
-  
+
   // test function form of callback
   User.find(1, {}, function(eric) {
     assertEquals('eric', eric.first_name);
     assert_changed();
   });
-  
+
   // test options form of callback
   User.find(1, {}, {on200: function(eric) {
     assertEquals('eric', eric.first_name);
     assert_changed();
   }});
-  
+
   // test onComplete is preserved
   User.find(1, {}, {onComplete: function(eric) {
     assertEquals('eric', eric.first_name);
     assert_changed();
   }});
-  
+
   // test that I can use options form but force it to be synchronous anyway
   var eric = User.find(1, {}, {asynchronous: false});
   assertEquals('eric', eric.first_name);
-  
+
   // test that I can omit the params hash completely if I pass a straight callback
   User.find(1, function(eric) {
     assertEquals('eric', eric.first_name);
     assert_changed();
   });
-  
+
   // test path prefixed find
   Resource.model(&quot;Post&quot;, {prefix: &quot;/users/:user_id&quot;})
   var post = Post.find(1, {user_id: 1})
   assertEquals(1, post.id)
   assertEquals(&quot;the body&quot;, post.body)
-  
+
   // test JSON find
   Resource.model(&quot;User&quot;, {format: &quot;json&quot;})
   var eric = User.find(1);
   assertEquals(&quot;Eric wasn't found through JSON find(1).&quot;, 'eric', eric.first_name);
   assertEquals(&quot;ID didn't get transformed using JSON.&quot;, 1, eric.id);
   assertEquals(&quot;1&quot;, eric.admin.toString());
-  
+
   // test Remote find
   Resource.model(&quot;User&quot;, {prefix: &quot;http://www.thoughtbot.com&quot;, format: &quot;json&quot;})
   var eric;
@@ -264,10 +264,10 @@ function testFind() {
   });
 }
 
-function testFindAll() {  
+function testFindAll() {
   var users = User.find('all');
   assertEquals(3, users.length);
-  
+
   var eric = User.find(1);
   for (var i =0; i&lt;eric._properties.length; i++)
     assertEquals(eric._properties[i], users[0]._properties[i]);
@@ -275,30 +275,30 @@ function testFindAll() {
   assertEquals(eric.constructor, users[0].constructor);
   for (var i=0; i&lt;3; i++)
     assertEquals(i+1, users[i].id)
-  
+
   User.find('all', {}, function(users) {
     assertEquals(3, users.length);
     assertEquals(eric.constructor, users[0].constructor);
     assert_changed();
   });
-  
+
   // test that there's no issue with one element arrays in XML
   Internet[User._list_url()] = allWithOneUserDetails;
   var users = User.find(&quot;all&quot;);
   assertEquals(1, users.length);
-  
+
   // with params
   var admins = User.find(&quot;all&quot;, {admin: true})
   assertEquals(2, admins.length);
   assertEquals(&quot;eric&quot;, admins[0].first_name);
   assertEquals(&quot;chad&quot;, admins[1].first_name);
-  
+
   // JSON find all
   Resource.model(&quot;User&quot;, {format: &quot;json&quot;})
   var users = User.find('all');
   assertEquals(&quot;Found eric as first user in JSON :all&quot;, &quot;eric&quot;, users[0].first_name)
   assertEquals(&quot;Found john as second user in JSON :all&quot;, &quot;john&quot;, users[1].first_name)
-  
+
   // Remote find all
   var users;
   User.find('all', {}, function(users) {
@@ -312,16 +312,16 @@ function testFindAll() {
 function testFindFirst() {
   var eric = User.find('first');
   var eric2 = User.find(1);
-  
+
   assertEquals(eric.first_name, eric2.first_name);
   assertEquals(eric.constructor, eric2.constructor);
-  
+
   User.find('first', {}, function(eric) {
     assertEquals(eric.first_name, eric2.first_name);
     assertEquals(eric.constructor, eric2.constructor);
     assert_changed();
   });
-  
+
   // with params
   var admin = User.find(&quot;first&quot;, {admin: true})
   assertEquals(&quot;eric&quot;, admin.first_name);
@@ -330,16 +330,16 @@ function testFindFirst() {
 // reload is a find operation
 function testReload() {
   var eric = User.find(1)
-  
+
   // fake that the user details got updated
   Internet[User._show_url(1)] = {'user': johnDetails}
-  
+
   eric.reload();
   assertEquals(&quot;john&quot;, eric.first_name)
-  
+
   // switch back
   Internet[User._show_url(2)] = {'user': ericDetails}
-  
+
   eric.reload(function(ignoreMe) {
     assertEquals(&quot;eric&quot;, eric.first_name)
     assert_changed();
@@ -357,10 +357,10 @@ function testAssociations() {
   assertEquals(&quot;posts&quot;, eric._associations[0]);
   assertEquals(Post, eric.posts[0].klass);
   assertEquals(2, eric.posts.length);
-  
+
   var john = User.find(2);
   assertEquals(1, john.posts.length);
-  
+
   // auto-model associations if need be
   var original_url = Post._show_url();
   Post = undefined;
@@ -371,7 +371,7 @@ function testAssociations() {
   assertEquals(&quot;post&quot;, Post._singular);
   assertEquals(User._format, Post._format);
   assertEquals(User._prefix, Post._prefix);
-  
+
   // belongs_to/has_one
   Resource.model(&quot;Post&quot;);
   Internet[Post._show_url(1)] = {'post': postIncludeDetails};
@@ -379,7 +379,7 @@ function testAssociations() {
   assertEquals(1, post._associations.length);
   assertEquals(&quot;user&quot;, post._associations[0]);
   assertEquals(User, post.user.klass)
-  
+
   // auto-model belongs_to/has_one
   var original_url = User._show_url();
   User = undefined;
@@ -399,7 +399,7 @@ function testAssociations() {
 
 function testValidCheck() {
   var user = User.build();
-  
+
   assert(user.valid());
   user.errors[0] = 'error';
   assert(! user.valid());
@@ -411,7 +411,7 @@ function testInvalidSave() {
   assert(user.new_record());
 
   Ajax = { Request : function (url, options) {
-    this.transport = { 
+    this.transport = {
       status : 200,
       responseText : &quot;&lt;errors&gt;&lt;error&gt;First name can't be blank&lt;/error&gt;&lt;/errors&gt;&quot;
     };
@@ -427,7 +427,7 @@ function testInvalidSave() {
   assert(! user.new_record());
 
   Ajax = { Request : function (url, options) {
-    this.transport = { 
+    this.transport = {
       status : 200,
       responseText : &quot;&lt;errors&gt;&lt;error&gt;First name can't be blank&lt;/error&gt;&lt;/errors&gt;&quot;
     };
@@ -447,15 +447,15 @@ function testInvalidSave() {
 
 function testDestroy() {
   var eric = User.build({id: 1})
-  Ajax = { Request : function (url, options) { 
+  Ajax = { Request : function (url, options) {
       this.transport = { status : 500 };
     }
   }
   assert(!eric.destroy());
   assertEquals(1, eric.id);
-  
+
   var eric = User.build({id: 1})
-  Ajax = { Request : function (url, options) { 
+  Ajax = { Request : function (url, options) {
       this.transport = { status : 200 };
     }
   }
@@ -467,7 +467,25 @@ function testDestroy() {
     assertEquals(eric, eric.destroy());
     assertNull(eric.id);
     assert_changed();
-  });  
+  });
+
+  // Path prefixed destroy
+  Resource.model(&quot;Post&quot;, {prefix: &quot;/users/:user_id&quot;});
+
+  var eric = User.build({id: 1})
+  var post = Post.build({id: 3, user: eric});
+  var uriRegEx = RegExp(&quot;/users/1/posts/3&quot;);
+  Ajax = { Request : function (url, options) {
+      assert(&quot;URL passed (&quot;+url+&quot;) does not match expected path: &quot;+uriRegEx, 
+             uriRegEx.test(url));
+      this.transport = { status: 200 };
+    }
+  }
+
+  Post.destroy({id: 3, user_id: 1});
+
+  assertEquals(post, post.destroy());
+  assertNull(post.id);
 }
 
 function testSaveNewRecord() {
@@ -484,7 +502,7 @@ function testSaveNewRecord() {
   assert(eric.save());
   assertEquals(1, eric.id);
   assertEquals(1, eric.attributes().id);
-  
+
   var eric = User.build({ 'first_name' : 'eric' });
   eric.save(function(saved) {
     assert(saved);
@@ -502,7 +520,7 @@ function testSaveExistingRecord() {
   }};
 
   assert(eric.save());
-  
+
   eric.save(function(saved) {
     assert(saved);
     assert_changed();
@@ -512,7 +530,7 @@ function testSaveExistingRecord() {
 function testSaveReloadsUponFullResponse() {
   // new record
   var john = User.build({'first_name' : 'john' });
-  
+
   Ajax = { Request : function (url, options) {
     this.transport = {
       status: 201,
@@ -520,24 +538,24 @@ function testSaveReloadsUponFullResponse() {
       responseText : ericXML
     }
   }};
-  
+
   john.save();
-  
+
   assertEquals(1, john.id);
   assertEquals(&quot;eric&quot;, john.first_name)
-  
+
   // existing record
   var john = User.build({'first_name' : 'john', 'id' : 2});
-  
+
   Ajax = { Request : function (url, options) {
     this.transport = {
       status: 200,
       responseText : ericXML
     }
   }};
-  
+
   john.save();
-  
+
   assertEquals(&quot;eric&quot;, john.first_name);
   assertEquals(1, john.id); // if the server changes the ID, so be it
 }
@@ -552,12 +570,12 @@ function testBuild() {
   Resource.model('User', {checkNew: true});
   var eric = User.build();
   assertEquals(3, eric._properties.length);
-  
+
   // test with checking new.json
   Resource.model('User', {checkNew: true, format: 'json'});
   var eric = User.build();
   assertEquals(3, eric._properties.length);
-  
+
   // test that specific attributes will override what new returns
   var eric = User.build({first_name: &quot;eric&quot;, admin: true, daisies: 5});
   assertEquals(4, eric._properties.length);
@@ -599,7 +617,7 @@ function testUpdateAttributes() {
 /********************************************
  ************* PARSING TESTS ****************
  ********************************************/
- 
+
 function testAttributesFromJSON() {
   eval('var json = ' + ericJSON);
   var attributes = User._attributesFromJSON(json);
@@ -607,12 +625,12 @@ function testAttributesFromJSON() {
   assertEquals(&quot;1&quot;, attributes.admin.toString()); // toString() since &quot;1&quot; == true
   assertEquals(&quot;eric&quot;, attributes.first_name);
   assertEquals(Date, attributes.created_at.constructor)
-  
+
   // test that the surrounding attributes hash is optional
   var attributes = User._attributesFromJSON({email: &quot;emill@thoughtbot.com&quot;, id: &quot;1&quot;});
   assertEquals(&quot;emill@thoughtbot.com&quot;, attributes.email);
   assertEquals(1, attributes.id);
-  
+
   assertEquals(false, User._attributesFromJSON({}));
   assertEquals(false, User._attributesFromJSON([]));
   assertEquals(false, User._attributesFromJSON(null));
@@ -630,11 +648,11 @@ function testErrorsFromJSON() {
   Resource.model('User', {format: 'json'});
   var eric = User.build();
   var errors = eric._errorsFrom(errorJSON);
-  
+
   assertEquals(2, errors.length);
   assertEquals(&quot;Name can't be blank&quot;, errors[0]);
   assertEquals(&quot;City can't be blank&quot;, errors[1]);
-  
+
   assertEquals(false, eric._errorsFrom(' '));
   assertEquals(false, eric._errorsFrom(''));
   assertEquals(false, eric._errorsFrom(null));
@@ -644,11 +662,11 @@ function testErrorsFromXML() {
   var errorXML = &quot;&lt;errors&gt;&lt;error&gt;Name can't be blank&lt;/error&gt;&lt;error&gt;City can't be blank&lt;/error&gt;&lt;/errors&gt;&quot;
   var eric = new User();
   var errors = eric._errorsFromXML(errorXML);
-  
+
   assertEquals(2, errors.length);
   assertEquals(&quot;Name can't be blank&quot;, errors[0]);
   assertEquals(&quot;City can't be blank&quot;, errors[1]);
-  
+
   assertEquals(false, eric._errorsFromXML(' '));
   assertEquals(false, eric._errorsFromXML(''));
   assertEquals(false, eric._errorsFromXML(null));
@@ -657,7 +675,7 @@ function testErrorsFromXML() {
 /********************************************
  ************ INTERNAL TESTS ****************
  ********************************************/
- 
+
  function testGlobalScope() {
   // IE7 compatibility
   assertEquals(&quot;IE7 incompatibility&quot;, User, window.User);
@@ -689,7 +707,7 @@ function testNameAccessors() {
   assertEquals('user', User._singular);
   assertEquals('users', User._plural);
   assertEquals(default_prefix(), User._prefix);
-  
+
   Resource.model(&quot;OrderLineItem&quot;);
   assertEquals('OrderLineItem', OrderLineItem._name);
   assertEquals('order_line_item', OrderLineItem._singular);
@@ -698,7 +716,7 @@ function testNameAccessors() {
   assertEquals('order-line-items', OrderLineItem._plural_xml);
   assertEquals(default_prefix(), OrderLineItem._prefix);
 }
-      
+
 function testPrefix() {
   Resource.model('User', {prefix: 'http://www.thoughtbot.com'});
   assertEquals(&quot;Absolute prefix.&quot;, 'http://www.thoughtbot.com', User._prefix);
@@ -715,7 +733,7 @@ function testPluralization() {
   Resource.model('Person');
   assertEquals('person', Person._singular);
   assertEquals('people', Person._plural);
-  
+
   // singular override
   Resource.model('Person', {singular: 'user'})
   assertEquals('user', Person._singular);
@@ -730,23 +748,23 @@ function testPluralization() {
 function testLocationUrls() {
   Resource.model('User', {prefix: 'http://www.thoughtbot.com'});
   var eric = User.build({id: 1})
-  
+
   assertEquals('http://www.thoughtbot.com/users/1.xml', eric._show_url());
   assertEquals('http://www.thoughtbot.com/users/2.xml', User._show_url(2));
   assertEquals('http://www.thoughtbot.com/users/2.xml', User._show_url({id: 2}));
   assertEquals('http://www.thoughtbot.com/users/1.xml?lite=true', User._show_url({id: 1, lite: true}))
   assertEquals('http://www.thoughtbot.com/users/1.xml?lite=true', eric._show_url({lite: true}))
-  
+
   assertEquals('http://www.thoughtbot.com/users.xml', User._list_url());
   assertEquals('http://www.thoughtbot.com/users.xml', User._list_url({}));
   assertEquals('http://www.thoughtbot.com/users.xml?admin=true&amp;name=eric&amp;lasers=5', User._list_url({admin: true, name: &quot;eric&quot;, lasers: 5}));
-  
+
   assertEquals('http://www.thoughtbot.com/users/new.xml', User._new_url());
   assertEquals('http://www.thoughtbot.com/users/new.xml?lite=true', User._new_url({lite: true}));
-  
+
   Resource.model('Post', {prefix: 'http://www.thoughtbot.com/users/:user_id'});
   var post = Post.build({id: 1})
-  
+
   assertEquals('http://www.thoughtbot.com/users/1/posts/1.xml', post._show_url({user_id: 1}));
   assertEquals('http://www.thoughtbot.com/users/1/posts/2.xml', Post._show_url({id: 2, user_id: 1}));
   assertEquals('http://www.thoughtbot.com/users/2/posts.xml', Post._list_url({user_id: 2}));
@@ -758,7 +776,7 @@ function testLocationUrls() {
 function testNewRecordCheck() {
   var eric = User.build();
   assert(eric.new_record());
-  
+
   eric.id = 1;
   assert(! eric.new_record());
 }</diff>
      <filename>test/jester_test.html</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>aa751bee8637de35a3d82029736343e9222409c3</id>
    </parent>
  </parents>
  <author>
    <name>Nat Budin</name>
    <email>nbudin@michiba.boston.datasynapse.com</email>
  </author>
  <url>http://github.com/thoughtbot/jester/commit/cc286ba6372c42994f64168f7e2833b44f8ceffd</url>
  <id>cc286ba6372c42994f64168f7e2833b44f8ceffd</id>
  <committed-date>2008-05-02T12:10:04-07:00</committed-date>
  <authored-date>2008-05-02T12:10:04-07:00</authored-date>
  <message>Test cases for path-prefixed destroy.</message>
  <tree>18f137ad7337d1011356e567816d5ff0e8810213</tree>
  <committer>
    <name>Nat Budin</name>
    <email>nbudin@michiba.boston.datasynapse.com</email>
  </committer>
</commit>
