AjaxSource commit POST ?Bug

edited November 2013 in Enyo 2.4
Hi @clinuz and @unwiredben,

Just wondering if line 101 of xhr.js (AjaxSource kind) should be rec.raw() instead of rec.toJSON()? Using toJSON results in postBody ending up as a string rather than parameters/values.

Thanks,
Cage

lines 97-105 of xhr.js

//* Uses "POST" if the _record_ is new, otherwise "PUT" for the method
commit: function (rec, opts) {
opts.method = rec.isNew? "POST": "PUT";
opts.url = this.buildUrl(rec, opts);
//opts.postBody = rec.toJSON();
opts.postBody = rec.raw();
this.go(opts);
},

Comments

  • Also, should Model's raw function include an "else if" clause if the attribute is an instanceof enyo.Model (I added it below)? And some kind of final fallback if it's none of the above?
    		raw: function () {
    var i = this.includeKeys,
    a = this.attributes,
    r = i? enyo.only(i, a): enyo.clone(a);
    console.log("RAWING", this.name, i, a, r);
    for (var k in r) {
    if ("function" == typeof r[k]) {
    r[k] = r[k].call(this);
    } else if (r[k] instanceof enyo.Collection) {
    r[k] = r[k].raw();
    }
    //Added these lines below to support correct return if model contained in another model.
    else if (r[k] instanceof enyo.Model) {
    r[k] = r[k].raw();
    }
    }
    return r;
    },
  • The postBody property is in accordance with the same property in enyo.AjaxProperties where it is a string to be supplied with a POST request.

    To your second comment yes and no. Yes because it has code for enyo.Collection and that it will have support for a to-one type relationship in the near future. No because technically there isn't any built-in support for the relationship so the fact that enyo.Collection is supported already is...inconsistent but shouldn't be a blocker.

    I will be working on relational soon.
  • Hi @clinuz, any updates on relational? I think I'm doing something very wrong because I can't get my version of relational working right - it keeps complaining of duplicates...thanks, Cage
  • @psarin, its a work in progress atm and under heavy development, trying to have it ready and thoroughly tested by 2.3.1 and, unfortunately no, we don't have a date set for that quite yet.
  • edited January 2014
    Okay, thanks. A couple of questions:

    1. In xhr.js, AjaxSource.commit function, I need to use rec.raw() instead of rec.toJSON() when POSTing; if I use the current version of rec.toJSON(), a string is submitted rather than parameter:value pairs in the postBody.
    		//* Uses "POST" method if the record is new; otherwise, "PUT".
    commit: function (rec, opts) {
    opts.method = rec.isNew? "POST": "PUT";
    opts.url = this.buildUrl(rec, opts);
    //opts.postBody = rec.toJSON();
    opts.postBody = rec.raw();
    this.go(opts);
    },
    2. In Store.js, Store.addRecord function, I changed the throw statement to a console.log (or warn) and added a rec=kinds[id]; line before it. This is to return the existing record (i.e., one with same primary key) so an existing record can be added to multiple collections. I did not want to use "ignoreDuplicates=true" because I actually don't want new instances created for same data.
    			// if a primaryKey was resolved to an actual value we add that now too but the same
    // is true for unique primaryKey values as is euid just it only matters from within the scope
    // of the kind
    if (id !== undefined && id !== null) {
    // here's the sanity check
    if (kinds[id] && kinds[id] !== rec) {
    // uh oh we've got a duplicate primaryKey for the record but it is possible that the
    // primaryKey is...somehow not a unique or useful property and the only unique property
    // is euid so this flag could be set
    if (!this.ignoreDuplicates) {
    rec = kinds[id];
    console.log( "enyo.Store.addRecord: duplicate record added to store for kind `" + rec.kindName + "` " +
    "with primaryKey set to `" + pkey + "` and the same value of `" + id + "` which cannot coexist " +
    "for the kind without the `ignoreDuplicates` flag of the store set to `true`");
    }
    } else {
    kinds[id] = rec;
    }
    }
    3. Please see http://forums.enyojs.com/discussion/1923/suggestion-for-raw-function-in-model-js#latest re: Model.raw() function (same issue as my Nov 2013 post above).

    Just wondering what your thoughts on these are?
  • edited February 2014
    @clinuz:

    Any comments on above questions 2 and 3 above? :)

    Re: #1, I understand that I need to change the contentType; however, looking at xhr.js and Ajax.js, it appears that the data in postBody is stringified before it gets to Ajax.request. Therefore Ajax.request will not look at Content-Type and pass it as a string to server?

    Just wondering if I should be opening bug/feature requests for above or not.

    Thanks.
    Cage
  • I'm having a similar issue with Ajax.
    In fact, i want to send params via GET, to add filters to my Collection fecth method.
    I was about to suggest to add a toParams / toQueryString / stringify method into enyo, because i don't want to depends on jQuery, or anything else than Enyo.

    So, I looked at enyo.Ajax.objectToQuery, but this method is completely wrong.

    I tried:
    enyo.Ajax.objectToQuery({tartiflette: [{'pouet': 'coucou', 'poulet': [43, 54, 53]},{'pouet': 'cosdfucou', 'poulet': [53, 5, 'ds']}, {'pouet': 'cz', 'poulet': [43,'dfsdf', 53]}]})
    I got something un-interpretable:
    tartiflette=%5Bobject%20Object%5D&tartiflette=%5Bobject%20Object%5D&tartiflette=%5Bobject%20Object%5D
    This is what I'm waiting for:
    tartiflette[0][pouet]='coucou'&tartiflette[0][poulet][0]=43&tartiflette[0][poulet][1]=54&&tartiflette[0][poulet][2]=53&&tartiflette[1][pouet]=cosdfucou&...
    This method MUST be corrected, to post Params from GET and POST.
    Here are some implementation I found, but codes are always dependent of its core library (like isArray, etc...):
    https://github.com/jquery/jquery/blob/master/src/serialize.js
    http://yuilibrary.com/yui/docs/api/files/querystring_js_querystring-stringify.js.html#l25

    Thanks !

  • @psarin,

    1. The way the source works now is merely its "default" behavior. Its an optional mechanism where one could drop it in without change if they were engineering their backend to match. In many cases that is not possible and when working with remote sources we have to make modifications. To modify the behavior the most straightforward way I think would be to sub-kind enyo.AjaxSource and overload the _commit_ to do what you need. In this particular case the abstraction was designed so you could do this with relative ease. I'm thinking of any ways to make this better.

    2. This will not be an issue after the work I'm doing now is released. For now, that may be the best thing to suit you in this case.

    3. Without having seen your comment before now, I've addressed this in my current work. So moving forward it will be more versatile :)
  • edited February 2014
    Thanks. Re: #1 (again, haha), shouldn't it match the behavior Enyo sets in AjaxProperties (and what's standard for servers accepting POST), which is:
    	/**
    The content for the request body for POST/PUT methods.

    When postBody is a Buffer or a String, it is passed verbatim in the request body.
    When postBody is an Object, the way it is encoded depends on the contentType:

    * application/json => JSON.stringify
    * application/x-www-urlencoed => url-encoded parameters
    * multipart/form-data => passed as fields in enyo.FormData (XHR2 emulation)
    */
    postBody: "",
    Thanks again for your great work with MVC.
  • @ artistix_fr, the form you're referring to as unintelligible is the encoded version of your serialized string. The browser does this if you don't. It is working exactly the same as the jQuery method except that it doesn't let you make it human readable. To see it this way use the browser's built in decodeURI method.
  • edited February 2014
    @clinuz, I disagree with your comment. enyo.Ajax.objectToQuery is supposed to reformat a JS object to an URI encoded String (less human readable than JSON, but still 'store' all the formatted data). This format has a more descriptive form, like obj[attr1][attr2]='atomicData'.

    But enyo's implemented version only formats correctly data if there are already atomic. But if we try to format an object, there is no recursion, so it prints "object Object", the best JS atomic interpretation of a non-atomic data. See the implemented versions of jQuery: they pass a prefix (the "path" of the parent which store the atomic propertie).

    I'm sure it must be corrected.

    @psarin: I think you're right, it also should fit AjaxProperties, formatting must match defined Content-Type. But if objectToQuery is not corrected, you would be able to only send simple data, but no complex objects.

    EDIT: Here is a little Fiddle to illustrate: http://jsfiddle.net/RT3ne/
    Traditionnal formatting can't serialize objects. Recursive formatting permits to have whole data in parameters. If we want to send Collections to server, we need to recursively format it, that's how HTML Forms naturally do.
    I need it in my project, my Rails backend will record nested attributes passed in parameters. Plus, some complex objects may need it. Current version only supports atomic data. I will try to implement recursive objectToQuery for my project, I will then make a pull request if nobody does.
  • @artistix_fr Did you ever submit a PR for a better implementation of objectToQuery?
Sign In or Register to comment.