Upon a user registration, I've added a new field for a Meteor user using React as my front end:
React component:
Accounts.createUser({
email: trimInput(this.state.email),
password: this.state.password,
username: trimInput(this.state.username),
regId: 1, // I need to access this to show/hide fields elsewhere.
});
Server:
// I assume this is how it's done?
Accounts.onCreateUser(function(options, user) {
user['regId'] = options.regId
return user
});
In meteor mongo I can see the newly added field: "regId": "1". Great. Now in browswer console: Meteor.user.find().fetch() does not include the field. Meteor.user().regId returns undefined. Huh?
What is the correct way to approach something like this?
I think previous answer is good, but you should improve in order to remove
Meteor.subscribe("userData");
in every controller by publish automatically.
`Meteor.publish(null, function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId},
{fields: {'regId': 1}});
} else {
this.ready();
}
});`
Based on the documentation, I needed to pub/sub the data:
Server:
Meteor.publish("userData", function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId},
{fields: {'regId': 1}});
} else {
this.ready();
}
});
Client:
Meteor.subscribe("userData");
Now you'll have access to Meteor.user().regId
Related
I want to have client-side access for a certain set of fields for ALL users while I would like to have access to even more fields for the current user only. How do I go about writing publish code to accomplish this?
Right from Meteor documentation:
Meteor.publish("userData", function () {
return Meteor.users.find({_id: this.userId},
{fields: {'other': 1, 'things': 1}});
});
And also:
Meteor.publish("allUserData", function () {
return Meteor.users.find({}, {fields: {'nested.things': 1}});
});
Hope this helps.
As mentioned above, the
Meteor.publish("userData", function () {
return Meteor.users.find({_id: this.userId},
{fields: {'other': 1, 'things': 1}});
});
and
Meteor.publish("allUserData", function () {
return Meteor.users.find({}, {fields: {'nested.things': 1}});
});
publish functions will push the data from the Users collection.
Subscribe with
Tracker.autorun(function () {
Meteor.subscribe("userData");
Meteor.subscribe("allUserData");
});
And the additional data will automatically go into the Users collection and be available in the Meteor.user() object.
My story with that:
I proceeded as documentation says, but encountered with weird behavior.
I had publish function, where I published whole profile and email object for current user (lets say userData) and just some subset for the other users (allUserData).
When I had -
Meteor.subscribe("allUserData");
Meteor.subscribe("userData");
On client side right after user logged in, I've received just allUserData data. Thats mean even for my logged in user (That user couldn't see his own email address). When I refresh browser, bug was fixed and I got properly allUserData for all users except one logged in, which has his proper userData (with mentioned email address).
What is interesting, if I changed the sequence of that subscriptions, bug was fixed.:
Meteor.subscribe("userData");
Meteor.subscribe("allUserData");
Putting into Meteor.autosubscribe(function () { }) doesn't changed anything.
Finally I tried put that subscription into Deps.autorun(function() { }) and explicitly add reactivity and the problem with sequence was resolved..:
Deps.autorun(function() {
Meteor.subscribe("allUserData", Meteor.userId());
Meteor.subscribe("userData", Meteor.userId());
// or
// Meteor.subscribe("userData", Meteor.userId());
// Meteor.subscribe("allUserData", Meteor.userId());
});
In publish function I just replace this.userId with userId from parameter.
With next bug which I encountered was, that I've got secret systemData object in profile user's object and that can see just admins, not regular logged in users. But although correct set publish function with 'profile.systemData': 0 that secret object could see all logged in users which looked into his profile object.
Probably it was because my publish function(s) somehow interfered with publish function in Meteor Account package:
// Publish the current user's record to the client.
Meteor.publish(null, function() {
if (this.userId) {
return Meteor.users.find(
{_id: this.userId},
{fields: {profile: 1, username: 1, emails: 1}});
} else {
return null;
}
}, /*suppress autopublish warning*/{is_auto: true});
Anyway I resolved it with help of method Account.onCreateUser() and adding systemData next to profile object, not into profile.
There starts my other problems :) see Meteor.loginWithPassword callback doesn't provide custom object in User accounts doc
PS: If I knew it at begin, I've put systemData object into special collection.
Im adding a field to a user's account on creation. This is working fine:
Accounts.onCreateUser((options, user) => {
user.groups = [2];
return user;
});
I need to make a function that allows the user to change this. When I run this from the front-end I get an error "update failed: Access denied"
Meteor.users.update(
{ _id: Meteor.userId() },
{
$set: { groups: [4, 5] },
},
);
In server/main.js I have:
Meteor.publish('currentUser', function() {
return Meteor.users.find({ _id: this.userId }, { fields: { groups: 1 } });
});
Do not make db updates from the client directly. No client can ever be trusted.
Having said that, there are two ways to deal with this:
ONE
As per the documentation :
By default, the current user’s username, emails and profile are
published to the client. You can publish additional fields for the
current user with:
// Server
Meteor.publish('userData', function () {
if (this.userId) {
return Meteor.users.find({ _id: this.userId }, {
fields: { groups: 1 }
});
} else {
this.ready();
}
});
Meteor.users.allow({
update: function(userId, user) {
return true;
/**
* Don't use `return true` in production!
* You probably need something like this:
* return Meteor.users.findOne(userId).profile.isAdmin;
*/
}
});
// Client
Meteor.subscribe('userData');
Meteor allow rules
TWO
Define a meteor method in the server and have the server update the relevant data for you AFTER it does some validations. Server code is always trusted.
server.js
Meteor.method({
updateGroups: function(data){
// make changes to the user record
});
I have a mobile app in development and I'm transforming one of the collections to get the user last seen time, avatar etc.
PlayerRecord.prototype = {
constructor : PlayerRecord,
getAssociatedUser: function () {
return Meteor.users.findOne( this.user_id );
},
lastSeenFormatted: function () {
var user = this.getAssociatedUser();
return (user && user.last_seen) ? user.last_seen : 'Never';
}
}
My problem is that, if the user last seen returns Never initially but then the user is seen, my string return over there is not updated...obviously.
How would you advise me to handle this situation?
Did you check whether any user had a value for last_seen? This field has to be explicitly published.
According to the Meteor docs (http://docs.meteor.com/#/full/meteor_user):
By default, the current user's username, emails and profile are
published to the client. You can publish additional fields for the
current user with:
// server
Meteor.publish("userData", function () {
if (this.userId) {
return Meteor.users.find({_id: this.userId},
{fields: {'last_seen': 1}});
} else {
this.ready();
}
});
// client
Meteor.subscribe("userData");
I would to show a list of all users, in my template.
I have:
//publications.js
Meteor.publish('users', function() {
return Meteor.users.find({}, { fields: {username: 1, profile: 1} });
});
//router.js
Router.route('/users/add/:_id?', {name: 'users.add', controller: 'UserAddController'});
UserAddController = RouteController.extend({
subscriptions: function(){
return [ Meteor.subscribe('hospitals'),
Meteor.subscribe('roles'),
Meteor.subscribe('users') ];
},
action: function() {
this.render('addUser', {
data: function(){
return { hospital_id : this.params._id }
}
});
}
});
//client
Template.listUsers.helpers({
users: function() {
return Meteor.users.find({});
}
});
But the list keep showing only the current logged-in user. I have created a list of users using Account.createUser() function What am I doing wrong?
Thanks.
You have to subscribe to a publication using this.subscribe() in subscriptions hook:
// a place to put your subscriptions
subscriptions: function() {
this.subscribe('items');
// add the subscription to the waitlist
this.subscribe('item', this.params._id).wait();
}
Or use waitOn:
// Subscriptions or other things we want to "wait" on. This also
// automatically uses the loading hook. That's the only difference between
// this option and the subscriptions option above.
waitOn: function () {
return Meteor.subscribe('post', this.params._id);
}
By default, Meteor publishes the current user. I see that you have a addUser template and a listUsers template. The problem is that while addUser is subscribed to the users publication, listUsers is not (this would depend on what else you have in your router of course). To fix this, change the call to this.render to render the listUsers template. Then, your users helper should work, and you can render the information however you like.
I tested this with my own app (the Microscope project from DiscoverMeteor) and it worked for me. Hope it works for you too. Comment here if not, and be sure to accept this answer if it worked. =)
I know this question has been asked numerous times but I am having a difficult time publishing this information.
In Accounts.onCreateUser I am adding a field like so
{
...
user['info'] = { email: options.email, is_admin: false};
}
I publish this information;
Meteor.publish('user', function() {
return Meteor.users.find({}, { fields: { info: 1} });
}
and
Meteor.subscribe('user');
After debugging the Publish query returns the correct information but that is never given to the client when I try to access Meteor.user(). Do I have to do something else to allow info to be access by Meteor.user()?
Any suggestions?
You'll want to use null to publish to the single user.
Meteor.publish(null, function() {
return Meteor.users.find({_id: this.userId}, {fields: {info: 1}});
});