I defined a model Group similar to all my models but while testing my routes noticed that my mocha test timed out on DELETE
I kept debugging and found that the callback for model.remove() was not being called
findByIdAndRemove worked, so did findOneAndRemoveand I reduced the model shcema to its bare bones so why god, why!! isn't it working.
var GroupSchema = new mongoose.Schema({
name: {
type: String,
default: function() {
return generateName();
}
}
});
turns out I had defined
GroupSchema.methods.add = function(user) {
//TODO
};
GroupSchema.methods.remove = function(user) {
//TODO
};
and left it empty which override the mongoose remove method -__-
I love Javascript but this is one of those moments where protecting functions from override would have been nice.
of course it wouldn't be simple, I would like to override a function and call it if I want, so it's not like I can complain about the feature.
thought of sharing my experience out there so that I might save someone else the frustration.
I think a good way to approach this from now on is to namespace my custom methods which is impractical
or generally just leave a console.log on empty methods that are under construction so that I know if they're called.
Related
I am using iron:router in my app and I have a controller that subscribes to one document in a collection by using a parameter in the path. I can access all of the documents in my collection on the server, so I know that there is stuff in there, but when I try to access the data that I subscribe to in the waitOn method of the controller, the data is undefined. Here is the relevant code for this problem.
Router code:
this.route('unit', { path: 'unit/:unitId', template: 'unit', controller: 'UnitController' });
UnitController = BaseController.extend({
waitOn: function () {
return Meteor.subscribe('getUnit', this.params.unitId);
},
data: function () {
var id = this.params.unitId;
templateData = {
unit: Collections.units.model(Collections.units.getUnit(id))
};
return templateData;
}
});
Publication:
Meteor.publish('getUnit', function(id) {
return Collections.units.data.find({ unitId: id });
});
Here I have created an object for various things to do with my collection(I only included the important parts here):
Collections.units = {
data: new Mongo.Collection("units"),
getUnit: function (id) {
return this.data.findOne({ unitId: id });
},
model: function(unitEntity) {
return {
unitId: unitEntity.unitId,
createdAt: unitId.createdAt,
packets: unitEntity.packets,
getLastPacket: function (id) {
return _.last(this.packets);
}
};
}
};
I have been trying to debug this for quite a while and I can do all the things to the collection I want to on the server and in the publish method, but when it gets to the controller, I can't access any of the info. In the data method this.params.unitId returns exactly what I want so that isn't the issue. Where the exception gets thrown is when I try to read properties of unitEntity when I'm making the model but that is just because it is undefined.
Have any ideas what I am doing wrong? Thanks in advance for any responses.
The main problem that I was trying to solve's solution was to wrap the code inside the data method inside of if (this.ready()){ ... } and add an action hook with if (this.data()) { this.render(); }. After I got the subscription to work, I found that Christian was right in the comments with saying that my controller setup might mess things up. It was causing other strange exceptions which I fixed by just moving the hooks to each route instead of using the controller. As for my Collections setup, it may be unconventional, but all of that is working fine (as of right now). I may want to set them up the standard way at a later point, but as of right now its pretty handy for me to do things with the collections with the methods already written in the object.
I'm currently working on an app whose database schema changes frequently. This rapid change creates a big problem for my front-end Angular code which consumes the backend JSON API (which I don't have much control over) via Restangular; take the following code for example:
<ul>
<li ng-repeat="item in items">
<h2>{{item.label}}</h2>
</li>
</ul>
There will be a lot of template tags like {{item.label}} scattered everywhere in the front-end code, so whenever the property name changes from, say "label" to "item_label", I'll need to remember where those tags are and change all of them. Of course, I could do a project wide search and replace, but that's not really ideal from an DRY stand point and it'll also be a maintenance nightmare.
My question is, does Angular (or Restangular) provide a way to map model property names to custom ones like this in Backbone?
That way, I can just have something like this
{
label: model.item_label
}
then next time when the "item_label" is changed to something else, I can just update it in this configuration object and not worry about all the references in the templates.
Thanks.
The idea with angular is that you can do whatever you want with the model. While this doesn't point you in any specific direction it does give you the opportunity to implement it in your own OO manner. Say you have an app that has a data object called ...Task a model for tasks might look like..
function Task(initJson){
this.name = initJson._name || 'New Task';
this.completed = initJson.is_completed || false;
this.doneDateTime = initJson.datetime || null;
}
Task.prototype = {
save: function(){
//do stuff with this and $http.put/post...
}
create: function(){
//do stuff with this and $http.put/post
}
//....etc
}
All of this might be wrapped up in a factory.
myApp.factory('TaskFactory',function($http){
var Tasks = []; //Or {};
//above constructor function...
//other helper methods...etc
return {
instance: Task,
collection: Tasks,
init: function(){} // get all tasks? run them through the constructor (Task), populate collection
};
})
You could then edit properties on your constructor (one place (for each data type), the only place). Although this isn't ideal if your using things like Restangular or $resource as they not equipped to be a large backing store but they just assume the properties that come across the wire, which for large, changing applications can sometimes be difficult to manage.
I ended up going with Restangular's setResponseExtractor config property based on this FAQ answer.
It looks like this:
Restangular.setResponseExtractor(function(response, operation, what, url) {
var newResponse = response;
angular.forEach(newResponse.items, function(item) {
item.label = item.item_label;
}
return newResponse;
}
I have some code that looks like:
var instance = new ModelA(element);
if(instance.isValid()){
CollectionA.add(instance);
}
Is there a better way to write this? Would prefer that either initializing ModelA or adding to CollectionA would fail or throw.
You have to override the constructor.
See here for more info.
Backbone has this baked right in. There is a validate method available in your model code which will get called before any save (You can also do it for set by passing {validate:true}
Here's a snippet from the backbone docs:
var Chapter = Backbone.Model.extend({
validate: function(attrs, options) {
if (attrs.end < attrs.start) {
return "can't end before it starts";
}
}
});
If validate returns anything, then the Backbone SAVE won't happen, but if it goes through your validate function cleanly without any returns, then it will go ahead with the save.
So I'm writing a whole bunch of vendor-specific files in node which all have a similar controller pattern, so it makes sense for me to cut them out and put into a common file.
You can see my common controller file here: https://gist.github.com/081a04073656bf28f46b
Now when I use them in my multiple modules, each consecutively loaded module is overwriting the first. This is because the file is only required once and passed dynamically through to each module on load (this allows me to add extra modules and these modules are able to add their own routes, for example). You can see an example module here: https://gist.github.com/2382bf93298e0fc58599
You can see here on line 53 I've realised that we need to create a seperate instance every time, so I've tried to create a new instance by copying the standardControllers object into a new object, then initialising the new object. This has zero impact on the code, and the code behaves in exactly the same way.
Any ideas guys? I'm in a bit of a jam with this one!
First thing I'd do is try to make things simpler and reduce coupling by invoking the single responsibility principle, et al.
http://www.codinghorror.com/blog/2007/03/curlys-law-do-one-thing.html
Put those Schemas into their own files, eg
models/client.js
models/assistant.js
models/contact.js
I've also found that embedded docs + mongoose is generally a PITA. I'd probably promote all those to top level docs.
You don't need to enclose your object's keys in quotes.
routes = {
list: function() {} // no quotes is aok
}
Also 'list' in typical REST apps is called 'index'. Anyway.
Ok, I'd break this up differently. Since you're requiring stuff from the index.js file in the middleware, they become tightly coupled, which is bad. in fact, I think I'd rewrite this whole thing so it was tidier. Sorry.
I'd probably replace your 'middleware' file with an express-resource controller
https://github.com/visionmedia/express-resource (built by author of express). This is a good framework for restful controllers, such as what you're building. The auto-loader is really sweet.
You may also want to look at: http://mcavage.github.com/node-restify/ It's new, I haven't tried it out, but I've heard good things.
Since what you're building is basically an automated mongoose-crud system, with optional overriding, I'd create an express-resource controller as your base
/controllers/base_controller.js
and it might look like
var BaseController = function() {} // BaseController constructor
BaseController.prototype.index = function() {
// copy from your middleware
}
BaseController.prototype.show = function() {
// copy from your middleware
}
BaseController.prototype.create = function() {
// copy from your middleware
}
// etc
module.exports = BaseController
Then I'd do something like:
/controllers/some_resource_controller.js
which might look something like:
var BaseController = require('./base_controller')
var NewResourceController = function() {
// Apply BaseController constructor (i.e. call super())
BaseController.apply(this, arguments)
}
NewResourceController.prototype = new Base()
NewResourceController.prototype.create = function() {
// custom create method goes here
}
module.exports = NewResourceController
Then to use it, you can do:
var user = app.resource(myResourceName, new ResourceController());
…inside some loop which sets myResourceName to be whatever crud you're trying to set up.
Here's some links for you to read:
http://tobyho.com/2011/11/11/js-object-inheritance/
http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/
Also, it sounds like you're not writing tests. Write tests.
http://www.codinghorror.com/blog/2006/07/i-pity-the-fool-who-doesnt-write-unit-tests.html
Just getting started with backbone.js, and one of the things I've noticed is that many of my models, collections and views share some very similar methods. I'd like to refactor them & call them from an extracted location (/lib?). I went searching for documentation and/or examples, and was surprised by how little I found (specifically, none). So, a few questions:
Is there a reason I'm overlooking as to why there are so few examples of backbone methods factored out into common libraries?
Is there a standard/agreed upon location in backbone projects for shared code?
Any backbone classes and/or common plugins to help store common methods?
Any ideas appreciated - thanks in advance.
(EDIT) Example added:
Take this code from a view. (Admittedly it's too short be actually worth refactoring, but its simplicity makes it a concise example)
destroy: () ->
#model.destroy()
#remove()
return false
Suppose I wanted to refactor it into:
destroy: () ->
restful_destroy_method(this)
which then called:
restful_destroy_method: (view) ->
view.model.destroy()
view.remove()
return false
from a common library. Any reason why nobody else seems to do this?
It depends on the situation, and what your common code is.
In the case of your example, what I might do would be to create a more specific View to extend from.
Apologies for the straight JavaScript, I'm not as fluent in CoffeeScript to use it in an answer.
DestroyableView = Backbone.View.extend({
destroy: function () {
this.model.destroy();
this.remove();
return false;
}
});
Then, instead of creating new Backbone.View()s, I'd create new DestroyableView()s. DestroyableView could have other common functions, or you could create several different parent definitions and use _.extend() to apply them all to a single object.
You can use a "Basic View" which own the generic methods :
// Create a Basic View which have all generic methods
var BasicView = Backbone.View.extend({
restful_destroy_method: function () {
this.model.destroy();
this.remove();
return false
}
});
// Create a view which herits the methods of BasicView
var ExampleView = BasicView.extend({
destroy: function () {
this.restful_destroy_method();
}
});
You can show an example on jsFiddle here : http://jsfiddle.net/Atinux/YDMNg/