Continuing my exploration of couchapp, I will try to get updates working... well. It took me a bit yesterday, but I was able to submit a normal web form as a PUT of a JSON representation of the form. The JSON was submitted, but rejected by the CouchDB server. Today, I hope to be able to PUT successfully and without losing data.
CouchDB rejected yesterday's PUTs because they did not contain a revision number. CouchDB will reject a PUT to an existing resource with an old or missing revision number as an optimistic locking violation. In other words, if CouchDB cannot verify that the submitted data is a modified version of the current data, the PUT is disallowed.
That should be easy enough to address—adding the revision number to the default values ought to be sufficient. It is going to be a bit of a pain to add all recipe attributes (ingredients, categories, etc.) to the default values so that they are not lost. I'll cross that bridge when I come to it.
Even before I try addressing the revision number issue, I noticed something while perusing source code: the
docForm()
couchapp method (which maps form fields into JSON to be PUTted) takes an id
attribute. Yesterday I was including the ID in the default template
attribute:$.CouchApp(function(app) {I convert that to use the
var docid = document.location.pathname.split('/').pop();
app.docForm("form#update-recipe", {
fields: ['title', 'summary', 'instructions'],
template: {type: "Recipe", _id: docid},
beforeSave: function(doc) {
alert("Here!");
},
success: function(res, doc) {
alert("Success!");
}
});
});
id
attribute:$.CouchApp(function(app) {I push the update to my DB:
var docid = document.location.pathname.split('/').pop();
app.docForm("form#update-recipe", {
id: docid,
fields: ['title', 'summary', 'instructions'],
template: {type: "Recipe"},
beforeSave: function(doc) {
alert("Here!");
},
success: function(res, doc) {
alert("Success!");
}
});
});
cstrom@whitefall:~/repos/relax$ couchapp push http://localhost:5984/eeeNow when I submit yesterday's form, my tracer bullet still hits (shows the
[INFO] Visit your CouchApp here:
http://localhost:5984/eee/_design/relax/index.html
alert("Here!")
dialog), but something strange happens. The update is successful:How on earth did that happen? I still have not added a revision number to the default JSON values. The only thing I changed was the
id
attribute. So how could that PUT work? Did CouchDB suddenly get all lenient with PUTs?Checking the update payload, I find the
_rev
attribute along with other attributes that I did not explicitly set (like prep_time):The answer is that couchapp does magic with the
id
attribute. The docForm()
method sees id
and decides that it is representing an update of an existing resource. As an update, it sets all of the default attributes from the existing document including the _rev
. That's pretty freaking cool!What is even cooler is that couchapp edit templates work for creates just as well as they do for updates. In fact the same form works for both create and update. If the
id
attribute is not present (e.g. the URL being accessed does not have a document ID at the end), then the form will POST to the database (creating a new record). If the id
attribute is set, then the form will PUT to that id
in the database.To verify this, I modify the edit show function slightly to handle null documents:
function(doc, req) {If I access the edit show document without a document ID (http://localhost:5984/eee/_design/relax/_show/edit), I get a blank form:
// !json templates.edit
// !json templates._header
// !json templates._footer
// !code vendor/couchapp/template.js
// !code vendor/couchapp/path.js
return template(templates.edit, {
title: (doc && doc.title),
docid: (doc && doc._id),
asset_path: assetPath(),
summary: (doc && doc.summary),
instructions: (doc && doc.instructions),
header: template(templates._header, {}),
footer: template(templates._footer, {})
});
}
The first time I submit that form, I see the POST to the DB in the logs:
[Sun, 21 Feb 2010 03:07:54 GMT] [info] [<0.437.0>] 127.0.0.1 - - 'POST' /eee/ 201If I resubmit, I see the PUT to the document ID what was created by the previous POST:
[Sun, 21 Feb 2010 03:09:01 GMT] [debug] [<0.438.0>] 'PUT' /eee/c7764bf194c11a93d37c91100002787c {1,1}Ah, I definitely see a use-case for the
beforeSave
callback in docForm()
—creating pretty IDs rather than accepting the default hash supplied by CouchDB.One thing I still do not know is why I get this document missing alert when I access the edit page without a document ID:
Hopefully, there is an easy way to avoid that. I will pick up there tomorrow.
Aside from that, this couchapp thing rocks!
Day #20
No comments:
Post a Comment