Collections Help + Best Practise Questions

Hi All,

I had a few questions around the use of simple-schema, collection2 and autoform. DIsclaimer: @aldeed, you are my hero. Questions refer to code below:

let Locations = new SimpleSchema({
locations: { type: Array, label: ‘Location’, optional: true },
‘locations.$’: { type: Object },
‘locations.$.address’: { type: [String], label: ‘Address’, optional: true },
‘locations.$.city’: { type: String, label: ‘City’, optional: true },
‘locations.$.state’: { type: String, label: ‘State’, optional: true },
‘locations.$.country’: { type: String, label: ‘Country’, optional: true },
‘locations.$.zipcode’: { type: String, label: ‘Zip Code’, optional: true }
});

Entities = new Mongo.Collection(‘entities’);

Entities.allow({
insert: () => false,
update: () => false,
remove: () => false
});

Entities.deny({
insert: () => true,
update: () => true,
remove: () => true
});

let EntitiesSchema = new SimpleSchema({
name: { type: String, label: ‘Name’, max: 200 },
description: { type: String, label: ‘Description’,
allowedValues: [‘public’, ‘private’],
autoform: {
options: [
{label: ‘Public Sector’, value: ‘public’},
{label: ‘Private Sector’, value: ‘private’}
]
}
},
locations: { type: Locations, label: ‘Location(s)’ }
});

Questions -

  1. With collections in general, in examples (on the web) i see rules around allow/deny for insert, update and remove. (a) Why do we need both allow and deny. I understand it is done as a safety precaution, can someone explain this a little bit more. (b) Why is there nothing for upsert, should this not also be in the rule set if insert, update and remove are there?

  2. So while the above code sample works nicely with autoform, what i would like to do is have a seperate table called locations, as in Locations = new Mongo.Collection(‘locations’); but still use it as an external in my entities schema. I have been trying to get it to work, but it crashes out with “(STDERR) ReferenceError: Locations is not defined”.
    Is this possible?

  3. Why do i want to do this? The idea is (say - i made up the example above) i have defined some entities, but i want to add predefined locations to the relevant entities. But i want to use locations in other contexts also. So in my app, a user can add multiple locations to an entity, after defining them. I can handle this in locations by adding a ‘isAssigned’ Boolean or something.

  4. More importantly, the next step is to define a simple-schema for Meteor.users as documented in collection2. Then i want to be able to assign users to my entity. This is the use case i am looking to be able to do. So in the app, multiple users can be assigned to a specific entity (i was thinking to do this by having entity specific roles).

Misc Questions:

  1. If I do not use Autoform, the model i generally follow is from meteor chef. So allow/deny rules on client side. Fine. But then the client side code calls a module in the server side which does the heavy lifting, so i know my code which makes db changes is not compromised in any way. I do not exactly understand how autoform does this even with the rules in place. [I just started playing with Autoform yesterday]

  2. How does pub/sub work with autoform. Say i use an autoform for my entities, as above, but break up into multiple collections (As i want to do). Does the final blaze template subscribe to multiple collections (which is what i’m thinking), or, as the collections have sub collections in them, this is not required.

  3. I was also looking at using dburles:collection-helpers but i cannot get my head around the pub/sub concept here. Would the helper not break this?

  4. I’m also having some problems trying to move the collections into packages and use AutoForm there. Not sure why… Did anyone else have issues here?

P.S. With the misc questions, i may have confused myself. If someone can explain it out like I’m 5, would be most appreciated.

P.P.S the meteor chef guy is also a champion.

Thanks so much.

Tat

  1. You do not need both, and in my opinion you should use only “deny” because “allow” is not always called. I created ongoworks:security for OngoWorks because I believe allow/deny are too confusing and prone to misuse. https://github.com/ongoworks/meteor-security
  • Allow/deny are used only if you call insert/update/remove in client code, and upserts are not allowed from client code, so that’s why you don’t need one for upsert.
  1. In the Locations schema, remove “locations” and “locations.$” keys, and remove “locations.$” prefix from all the other keys. Then in EntitiesSchema, set “locations” type to Array and set “locations.$” type to Locations. You can store them in a separate Locations collection, too, but there isn’t built in support for this kind of joining. You’d have to submit your form to a method, split out those array items, save them to Locations collection, and then store an array of _id Strings in the locations array.
  • The reference error would be because you have to define Locations variable above where you’re using it, or in a file that gets loaded earlier.

Misc

  1. Autoform saves data however you want depending on what type of form you use. If it is method type, then it sends the object to that method and you save it on the server however you want. If it is insert or update type, then it calls insert or update on the client, so you need proper allow/deny security for that to work.
  2. Autoform doesn’t do pub/sub. You should subscribe to whatever data the form needs before displaying it.
  3. collection-helpers has nothing to do with pub/sub, except that if you define the helpers in"both" code, then they will only work on the client if you subscribe to all the necessary data before calling them.
  4. Just make sure the package itself lists autoform/c2/simple-schema as dependencies and it should work.
1 Like

Hi @aldeed,

Thanks very much for the above. I gave it a shot today and it is working really well. I’ll put it up my work in a bit so anyone else looking for this can also see it.

I have another question though. Using the logic you provided, i implemented Entities and Locations (partially anyways). Then i implemented Users by adding the schema you have in C2.

In effect, i created a field called tempPassword in the Users Schema. I take this tempPassword and then in a server method call Accounts.createUser. I never save tempPassword.

This allows me to simply have a Create User template with:

{{> afQuickField name=‘emails.0.address’}}
{{> afQuickField name=‘tempPassword’}}

in the autoForm. I am thinking i can also add in a onSubmit hashing hook so a hashed version of the password goes to my Meteor.methods({insertUser…}); in the server. This way the tempPassword can be used in Accounts.createUser. I also never save tempPassword anywhere.

Is this good practise or am i opening up some giant security hole?

Alternately how would i create a field in autoForm which has no direct field in the schema? The context is like an admin function where the admin user creates users/passwords or needs to reset passwords for locked out users.

Thanks so much.

Tat

In general as long as you are using TLS, sending plain password or hashed password is fine. Obviously every extra precaution helps. But ultimately the main thing is to make sure you have TLS.

If you are using schema attribute on the form, then simply add all the fields to that schema, even if you don’t ultimately save them. If you are using collection attribute and it derives the schema from the one attached to that collection, then add a separate schema attribute that points to your form schema, which can have the extra fields not stored in the collection.

Ok - i think i understand. I’m going to spend some time understanding this and trying out some stuff.

Thank you very much for your help on the above. You’re a legend. Thanks so much.