Collection Methods


#1

I’d like to be able to define Meteor methods for each Collection, that can be called the same way as dburles:collection-helpers, so I’ve made this function. It also fetches the user and document for you, as that’s something you always need for validation, and it also saves all actions to a log.

What do you guys think? I don’t think there should be any security issues, right?

Example usage

Todos.methods({
	check(){
		//this.doc and this.user are "secure" as they're fetched on the server
		if(!_.includes(doc.owners, user._id){
			throw new Error('denied')
		} else if(_.find(this.doc.tasks, task => !task.done)){
			throw new Error('all tasks are not done')
		} else {
			Todos.update(this.doc._id, {$set:{done:{user:this.user._id, date:new Date()}}})
		}
	},
	updateDescription(description){
		if(!_.includes(doc.owners, user._id){
			throw new Error('denied')
		} else {
			Todos.update(this.doc._id, {$set:{description}})
		}
	}
})

Then you can call the helpers/methods on the client like this:

let todo = Todos.findOne()
todo.check()
todo.updateDescription('new description')

Here’s the code

//Create a meteor method and a collection helper for each "Collection method"
Mongo.Collection.prototype.methods = function(methods){
	let collection = this
	_.each(methods, (fn, name) => {
		let methodName = collection._name + '-' + name
		Meteor.methods({
			[methodName](id, ...args){
				//Meteor method, runs on both client and server
				let doc = collection.findOne(id)
				let user = Users.findOne(this.userId) //it always requires that the user is logged in, which is fine for my app
				if(doc && user){
					fn.call({doc, user}, ...args)
					if(Meteor.isServer){
						Log.insert({
							date:new Date(),
							userId:this.userId,
							collection:collection._name,
							action:name,
							docId:id,
							args:args
						})
					}
				}
			}
		})
		collection.helpers({
			[name](...args){
				//Collection helper which calls the method
				Meteor.call(methodName, this._id, ...args)
			}
		})
	})
}