About Tutorial Step 10


#1

There were some confusing points in step 10 that I’ve outlined below:

  1. It wasn’t clear where to add the methods (10.2). I initially added the methods inside the if (Meteor.isClient) {...} block only, but I kept getting the “Method not found [404]” error. It was only when I reread the instructions carefully that I noticed the part where it said “methods should be defined in code that is executed on the client and the server,” so I added the methods inside the if (Meteor.isServer) {...} block as well, and the error went away. However, adding the same code in two locations didn’t sit well with me, so I ended moving the Meteor.methods({...}) code inside an initMethods() function and calling that function twice.

  2. The tutorial states “When we insert tasks into the database, we can now securely verify that the user is logged in, that the createdAt field is correct, and that the owner and username fields are correct and the user isn’t impersonating anyone.” However, these aren’t implemented in the tutorial; the only check is an if (!Meteor.userId()) in the addTask method, which doesn’t come into play because there’s already an {{#if currentUser}} condition that hides the form in the template if the user is not logged in. I wish the tutorial would also demonstrate how to do these additional checks using best practice. For example, show how you would code logic that would allow a user to delete a task only they added the task. It wasn’t as easy as I thought to return a string from a MongoDB key given a record ID (_id), so I eventually settled with this:

deleteTask: function(taskId) {
  if (!Meteor.userId() || Meteor.userId()!==Tasks.find(taskId, {fields:{owner:1}}).fetch()[0].owner) {
    alert('You do not have permission to perform this action.');
    throw new Meteor.Error('not-authorized');
  }
  Tasks.remove(taskId);
},

Is there an easier or more concise way to do this?

UPDATE: I found a simpler way to do this in step 11…

var task = Tasks.findOne(taskId);
if (task.owner!==Meteor.userId()) { ... }

#2

You could make that more efficient by following what the tutorial was doing with fields:

var task = Tasks.findOne(taskId, {fields: {owner: 1}});

Only retrieve the fields you really need. If you just do Tasks.findOne(taskId) and that document has 500 fields, that’s no good.