Meteor user profile update - meteor

This Meteor client code is trying to update the current user profile with a new property header if it does not exist and asign to it a value from a variable menuShortName
The below code is crashing the app, it does not like ['header'] How can it be done? Thanks
I need to have both server and client be able to modify this value.
Meteor.users.update({_id: userId},{$set: {profile['header']: menuShortName}});

Your syntax is close. You must wrap nested properties in quotes:
Meteor.users.update({_id: userId}, {$set: {'profile.header': menuShortName}});

Related

Check if username exists in Meteor

Been digging around for a solution but none for Meteor. If any, please let me know. I want to check if a username is already taken.
I understand that this only works on the server side only:
u = Accounts.findUserByUsername('foo');
console.log(u.username); #=> foo
I cant get my head around their pub/sub as I can only see information based on the current user. Is meteor saying that what I want is not possible?
When a user is filling out their details upon registration, I want them to be alerted (as they type) if the username they are using is already taken. But that logic I can easily code but need to know how to talk to the server to tell me the information.
You could write a Meteor method for that:
Meteor.methods({
doesUserExist(name) {
return Accounts.findUserByUsername(name) != null;
}
});
Note that you have to define this method on the server but not on the client (e.g., by defining it in a file inside the server directory). That way Meteor won't try to simulate it on the client (which would fail because Accounts.findUserByUsername is not defined there).
Call the method as the user types:
Meteor.call('doesUserExist', name, function(error, result) {
// `result` is true if the user exists.
});

How can I make a Meteor publish method reactive to a server-side parameter?

I have a publication based on server-side user permissions. I want it to be reactive to changes in these permissions.
// SERVER CODE
Meteor.publish("my_publication", function(parent_id) {
//fetch our parent record and lookup this user's permissions
var parent = ParentCollection.findOne({_id: parent_id});
var myPermissionsList = parent.permissionsDict[this.userId];
//use these permissions to make our query
ChildCollection.find({parent_id: parent_id, permissions: {$in: myPermissionsList}})
}
// CLIENT CODE
Tracker.autorun(function () {
Meteor.subscribe('my_publication', Session.get("my_parent_id"));
});
This properly returns all the elements of the "child" collection specified parent, as long as the parent says the user has at least one of the permissions in the child element's list. It does this without the user actually knowing what their permissions are, which is a requirement.
This behaves like one would expect in Meteor:
The subscription does automatically update if any of the returned ChildCollection elements are changed.
The subscription does automatically update if the client changes the "my_parent_id" Session variable, triggering the Tracker.autorun resubscribe.
The subscription does not automatically update if the permissions used to make the query (parent.permissionsDict[this.userId]) are changed.
We're looking for the best (highest performing) way to get an automatic update in the last case.
This article was a helpful, more detailed resource on the topic:
https://www.discovermeteor.com/blog/reactive-joins-in-meteor/
My current understanding is that I need to utilize cursor.observeChanges() to react to changes in my permissions query. However, I am not sure how this fits into the rest of the Meteor publish/subscribe model--where would I call this, and how could the callback instruct Meteor to republish "my_publication"?
I believe https://atmospherejs.com/mrt/reactive-publish addresses this, but I feel like I should try to get a better grasp on core reactivity in meteor before turning to an external package. I also lack an understanding about the performance costs.
Any help would be greatly appreciated!
You can use the reactive-publish package (I am one of authors):
Meteor.publish("my_publication", function(parent_id) {
this.autorun(function (computation) {
//fetch our parent record and lookup this user's permissions
var parent = ParentCollection.findOne({_id: parent_id}, {fields: {permissionsDict: 1}});
var myPermissionsList = parent.permissionsDict[this.userId];
//use these permissions to make our query
return ChildCollection.find({parent_id: parent._id, permissions: {$in: myPermissionsList}});
});
}
It is important that you limit the fields you are interested in the parent document, otherwise autorun would rerun every time any field changes in the document, even if you do not care/use that field.

Accounts.createUser create users, but only from the server and not allow the client to create user

first excuse my writing, I'm using google translator.
What I want is to create users meteor, but only from the server and not allow the client to create users.
try putting
Accounts.validateNewUser (function () {
return false;
});
but it denies me create users to the server (which I do not want)
thank you very much in advance.
You can use Accounts.config for that purpose. Just anywhere in your server code do
Accounts.config({
forbidClientAccountCreation: true,
});
One way to do this would be to add some kind of un-guessable string to the profile key when you create a user on the server, check for that key in the validateNewUser function and then remove it immediately using observe on an appropriate cursor.
On the server you would have:
Accounts.validateNewUser(function(user) {
return (user.profile && user.profile.createUserKey === [KEY]);
});
Meteor.users.find().observe({
added: function(user) {
Meteor.users.update(user, {$unset: {'profile.createUserKey': true}});
}
});
And then your server-side createUser line looks like this (along with any other data you want to pass in the profile):
Accounts.createUser({username: [USERNAME], password: [PASSWORD], profile: {createUserKey: [KEY]}});
Assuming you don't publish the validation function anywhere (like Github), a client will have no way of knowing what the key is and would thus be unable to create a new user. If you don't trust yourself not to push it to Github or similar, store the key in an unpublished collection in your MongoDB and then pull it out on server start-up - that's what I do.
NOTE I think it's slightly unsatisfactory that I'm using a cursor here as it would be far better to remove the key in an onCreateUser callback, but this seems to be called before validateNewUser, so it's no use here. The alternatives are using your own modified version of the createUser function in the Accounts package, which probably isn't too tough but is a little involved to go into here, or just leaving the key in the user document and making sure you don't publish it.

meteor: no page updates after updating collection

I have published and subscribed successfully two collections. On client side, i put the subscribe method into an autorun function and my collections updates every time i change some session variables. My data model looks like the following:
Topics: {
_id: ObjectID,
comments: [
commentId1,
commentId2,
etc...
]
}
Comments: {
_id: ObjectID,
}
When i create a new comment, i insert the comment in the Comments collection and update the Topics collection with a $push on the array. After this i expected, that meteor re-renders my page, but this happens only if i change my topic session variable and change it back or reload the page manually... Only then meteor renews the subscription.
Why is this so? I think i missed something... But the docs gave me no clues.
I guess, the reason is that you are performing database insertion on client side, but can't tell why it's not rendering page again.
One more way you can do that is, perform insertion on server side using Meteor.call() as:
if (Meteor.isClient){
....
....
Meteor.call('addComment', 'your_new_comment');
....
}
And on the server-side:
if(Meteor.isServer){
Meteor.Methods({
'addComment' : function(data){
//your insertion code here.
Comments.insert(data);
}
});
}
The same you can do for Topics also. This will update the relevant data on server-side, and because you have already published-subscribed those data, it will be automatically published on client, even though the session variable doesn't changes.

In Meteor, how do I show newly inserted data as greyed out until it's been confirmed by the server?

Say my application has a list of items of some kind, and users can insert new items in the list.
What Meteor normally does is: when a user inserts an item in the list, it appears in their browser immediately, without waiting for server confirmation.
What I want is: when an item is in this state (submitted but not yet acknowledged by the server), it appears at its correct position in the list, but greyed out.
Is there a way to make Meteor do this?
Sure. Make a method that does the insertion. When the method runs, have it check to see if it is running in simulation, and if so, set a 'temporary' or 'unconfirmed' flag on the inserted item. Use that to decide whether to render the item as greyed out.
Assuming you're using MongoDB:
// Put this in a file that will be loaded on both the client and server
Meteor.methods({
add_item: function (name) {
Items.insert({name: name,
confirmed: !this.isSimulation});
}
});
Calling the method:
Meteor.call("add_item", "my item name");
That's all you need to do. The reason this works is that once the server has finished saving the item, the local (simulated) changes on the client will be backed out and replaced with whatever actually happened on the server (which won't include the 'unconfirmed' flag.)
The above is the simplest way to do it, but it will result in all of the
records in your database having a 'confirmed' attrbiute of true. To avoid this, only set the confirmed attribute if it's false.
Refer to this part of documentation for more information about isSimulation and Meteor.methods
This is what I did added an observer on the server side,
I created a variable called notify false from the client side itself
once the server receives the udpate it will make notify true and the client will be updated on the same.
Collection.find({"notify":false}).observe({
"added" : function(first){
collection.update({"_id":first._id},{$set : {"notify":true}});
}
});

Resources