Permalink
Browse files

Working on Mobius' killer feature -- functional browser-side models, …

…with a JQuery bridge -- in the process found a problem with the way update functionality worked. I have changed how GUIDs are generated for documents stored in MongoDB.
  • Loading branch information...
1 parent fa26c20 commit 605fc356dc90774b056afea9f6e18e69c65bcc67 @bcoe committed May 23, 2010
@@ -5,7 +5,7 @@ exports.BlogPost = MobiusController.extend({
if (this.params['BlogPost']) {
try {
- MobiusModel.BlogPost.create(this.params['BlogPost']);
+ MobiusModel.BlogPost.update(ObjectID.createFromHexString(this.params['BlogPost']['_id']), this.params['BlogPost']);
} catch (e) {
for (var key in e.errors) {
sys.puts(e.errors[key]['msg']);
@@ -21,5 +21,27 @@ exports.BlogPost = MobiusController.extend({
self.post = results[0];
}// callback.
);
+ },
+
+ create: function() {
+ var payload = {success : 'true'}
+
+ if (this.params) {
+ try {
+ MobiusModel.BlogPost.update({_id : this.params._id}, this.params);
+ } catch (e) {
+ sys.puts(e);
+ for (var key in e.errors) {
+ sys.puts(e.errors[key].msg);
+ }
+ }
+ }
+
+ // Check whether we should return a JSON payload.
+ for (var key in this.accepts) {
+ if (this.accepts[key] == 'application/json') {
+ this.render_text(JSON.encode(payload));
+ }
+ }
}
});
@@ -5,4 +5,4 @@ Date: <i><%= post ? post.date : '' %></i>
</p>
<%= partial('awesome.html.mejs') %>
<hr />
- <%=form( MobiusModel.BlogPost )%>
+ <%=form( MobiusModel.BlogPost, {'object' : post, 'action' : 'update'} )%>
View
@@ -26,10 +26,15 @@
return false;
} else {
- console.log(params);
- return true;
+ client.create(modelName, function() {
+ alert('created the model!')
+ });
+ return false;
}
- }
+ },
+ modelName: 'BlogPost',
+ route: '/blog/create',
+ action: 'create'
});
});
View
@@ -14,6 +14,13 @@
},
{
+ "route" : "/blog/create",
+ "method" : "post",
+ "controller" : "blog-post",
+ "action" : "create"
+ },
+
+ {
"route" : "/catalogue",
"method" : "get",
"controller" : "catalogue",
@@ -60,5 +67,12 @@
"method" : "get",
"type" : "static",
"path" : "lib/resig/resig.js"
+ },
+
+ {
+ "route" : "/lib/client-processing-stack.js",
+ "method" : "get",
+ "type" : "static",
+ "path" : "lib/mobius-js/client-processing-stack.js"
}
]
@@ -0,0 +1,152 @@
+/**
+ * Mobius-JS
+ * /\ \
+ * / \ \
+ * / \ \
+ * / \ \
+ * / /\ \ \
+ * / / \ \ \
+ * / / \ \ \
+ * / / / \ \ \
+ * / / / \ \ \
+ * / / /---------' \
+ * / / /_______________\
+ * \ / /
+ * \/_____________________/
+ *
+ * Benjamin Coe (BenjaminCoe.com) - MIT Licensed.
+ *
+ * Description: This class is used by models on the client-side of mobius
+ * to exose AJAX model operations.
+ */
+
+/**
+ * A Mobius processing-stack inherits from a Resig class.
+ */
+var ProcessingStack = resig.Class.extend( {
+ processingStack: []
+});
+
+/**
+ * Synchronous processing stack abstracts away asynchronous behavior.
+ * Note: Do not access this method directly, instead use ProcessingStack.extend({});
+ *
+ * @type void
+ * @public
+ */
+ProcessingStack.prototype.init = function() {
+ var self = this; // Store reference to 'this' for closures.
+
+ setTimeout(function() {
+ self._processStack(self);
+ }, 10);
+},
+
+/**
+ * Called by a model to place a create operation on the stack.
+ *
+ * @param {object} params key value pairs for creating a new model.
+ * @param {function} callback function to execute upon this operations completion.
+ * @type void
+ * @public
+ */
+ProcessingStack.prototype.create = function(params, callback) {
+ callback = callback || function() {};
+ this.processingStack.push([function(self, params, callback) {
+
+ $.ajax({
+ url: params.route,
+ dataType: 'json',
+ data: params.values,
+ success: callback,
+ type: 'POST'
+ });
+
+ }, params, callback]);
+},
+
+/**
+ * Called by a model to place an update operation on the stack.
+ *
+ * @param {object} params key value pairs for creating a new model.
+ * @param {function} callback function to execute upon this operations completion.
+ * @type void
+ * @public
+ */
+ProcessingStack.prototype.update = function(params, callback) {
+ callback = callback || function() {};
+ this.processingStack.push([function(self, params, callback) {
+
+ }, params, callback]);
+},
+
+
+/**
+ * Called by a model to place a remove operation on the stack.
+ *
+ * @param {object} params key value pairs for creating a new model.
+ * @param {function} callback function to execute upon this operations completion.
+ * @type void
+ * @public
+ */
+ProcessingStack.prototype.remove = function(params, callback) {
+ callback = callback || function() {};
+ this.processingStack.push([function(self, params, callback) {
+
+ }, params, callback]);
+},
+
+/**
+ * Called by a model to place an operation on the stack which initializes model indexes.
+ *
+ * @param {object} params key value pairs for model index creation operation.
+ * @param {function} callback function to execute upon this operations completion.
+ * @type void
+ * @public
+ */
+ProcessingStack.prototype.createIndex = function(params, callback) {
+ callback = callback || function() {};
+ this.processingStack.push([function(self, params, callback) {
+
+ }, params, callback]);
+},
+
+/**
+ * A stack operation that returns models from the database as a parameter
+ * to the callback provided.
+ *
+ * @param {object} Parameters for restricting and sorting the models returned from the DB.
+ * @param {function} callback function to return all models retrieved to.
+ * @type void
+ * @public
+ */
+ProcessingStack.prototype.find = function(params, callback) {
+ this.processingStack.push([function(self, params, callback) {
+
+ }, params, callback])
+},
+
+/**
+ * Consumes from the processingStack and performs asynchronous operations
+ * in a synchronous fashion.
+ *
+ * @param {object} self a reference to the processing stack.
+ * @type void
+ * @private
+ */
+ProcessingStack.prototype._processStack = function(self) {
+ var callMe = self.processingStack.shift();
+ if (callMe) {
+ callMe[0](self, callMe[1], function(data) {
+ callMe[2](data);
+ setTimeout(function() {
+ self._processStack(self);
+ }, 10);
+ }); // Call the action of this controller.
+ } else {
+ setTimeout(function() {
+ self._processStack(self);
+ }, 10);
+ }
+}
+exports.ProcessingStack = ProcessingStack;
@@ -66,6 +66,7 @@ MobiusController.prototype.execute = function(controller, action, express) {
this.express = express;
this._loadParams();
this._loadCookies();
+ this._loadAccepts();
this._invokeAction(this.action);
if (!this.rendered) {
@@ -97,6 +98,36 @@ MobiusController.prototype.render = function(view, options) {
},
/**
+ * Thin wrapper for the express object. Allows classes that extend
+ * the MobiusController to call this.render_text.
+ *
+ * @param {string} encoding the encoding for the response
+ * @param {string} content the content to render.
+ * @type void
+ * @public
+ */
+MobiusController.prototype.render_text = function(content) {
+ var options = options || {};
+ this.rendered = true;
+ this.mobiusProcessingStack.render_text({
+ self : this,
+ content : content
+ }, this._render_text);
+},
+
+/**
+ * Allow a controller to output text content. Useful for JSON payloads.
+ *
+ * @param {object} params
+ * @type void
+ * @private
+ */
+MobiusController.prototype._render_text = function(params) {
+ params['self']._setCookies();
+ params['self'].express.respond(200, params.content, 'utf-8');
+},
+
+/**
* We must ensure that rendering is the last action that takes place
* when calling the mobius controller. For this reason, the render step
* is dispatched to the mobius processing stack and actually performed
@@ -182,6 +213,23 @@ MobiusController.prototype._setCookies = function() {
}
/**
+ * Build an array of content types that the HTTP
+ * request accepts.
+ *
+ * @type void
+ */
+MobiusController.prototype._loadAccepts = function() {
+ this.accepts = []; // List the types accepted in a response.
+
+ var acceptAll = this.express.header('accept');
+
+ var tempTypes = acceptAll.split(/, ?/);
+ for (var key in tempTypes) {
+ this.accepts.push(tempTypes[key]);
+ }
+}
+
+/**
* Merge get and post parameters into the same struct.
* call helper functions to create arrays from magic
* post syntax.
@@ -22,6 +22,7 @@
// Dependencies.
var sys = require('sys');
var mongo = require('mongodb');
+var bson = require('mongodb/bson/bson')
var OPERATION_TIMEOUT = 5000;
/**
@@ -213,11 +214,14 @@ MongoDBConnector.prototype.create = function(self, params, callback) {
}
}, OPERATION_TIMEOUT);
- self.db.collection(params['collectionName'], function(err, collection) {
+ self.db.collection(params.collectionName, function(err, collection) {
+ // Generate a unique GUID for this object.
+ var guid = new bson.ObjectID;
+ params.values._id = guid.toHexString();
var results = {};
// Insert the model.
- collection.insert(params['values'], function(err, docs) {
+ collection.insert(params.values, function(err, docs) {
success = true;
callback();
});
@@ -248,11 +252,14 @@ MongoDBConnector.prototype.update = function(self, params, callback) {
}
}, OPERATION_TIMEOUT);
- self.db.collection(params['collectionName'], function(err, collection) {
+ self.db.collection(params.collectionName, function(err, collection) {
+ // Make sure the _id parameter is not being updated
+ // since this is not allowed.
+ delete params.values._id;
var results = {};
// Insert the model.
- collection.update(params['restrict'], new mongo.OrderedHash().add("$set", params['values']), function(err, docs) {
+ collection.update(params.restrict, new mongo.OrderedHash().add("$set", params.values), function(err, docs) {
success = true;
callback();
});
Oops, something went wrong.

0 comments on commit 605fc35

Please sign in to comment.