I'm building an application where teachers and students interact. I trying to publish the classes for teacher/student relationship. How do I publish classes which contain the teacherUserId and the studentUserId.
Path: publish.js
Meteor.publish('classes', function(group){
if (Roles.userIsInRole(this.userId, ['is_teacher'], group)) {
check(id, String);
return Classes.find({teacherUserId: this.userId, studentUserId: id});
} else {
// user not authorized. do not publish secrets
this.stop();
return;
}
});
Path: class.js
Template.classes.onCreated(function() {
var self = this;
self.autorun(function(){
self.subscribe('classes');
});
});
Template.classes.helpers({
studentProfileId: () => {
return FlowRouter.getParam('id');
}
});
Related
I'm trying to return only the data for a specific user. However my return classes.find doesn't return anything. What am I doing wrong?
Template.classes.helpers({
studentProfileId: () => {
return FlowRouter.getParam('id');
}
classes: ()=> {
return Classes.find({id: studentProfileId});
}
});
You need to make the data available to the client:
Template.classes.onCreated(function() {
this.subscribe('Classes', FlowRouter.getParam('id'));
});
and to use a variable in the helpers as well..
Template.classes.helpers({
classes: function() {
return Classes.find({studentProfileId: FlowRouter.getParam('id')});
}
});
I needed to create a variable and use FlowRouter.getParam to access the user id.
Template.classes.helpers({
studentProfileId: () => {
return FlowRouter.getParam('id');
}
classes: () => {
var id = FlowRouter.getParam('id');
return Classes.find({studentProfileId: id});
}
});
I have a meteor project where all my users have their own profile page setup in this way using routes:
Routes code:
Router.route('/#:username', {
name: 'profile',
controller: 'ProfileController'
});
ProfileController = RouteController.extend({
template: 'profile',
waitOn: function() {
return Meteor.subscribe('userProfile', this.params.username);
},
data: function() {
var username = Router.current().params.username;
return Meteor.users.findOne({
username: username
});
}
});
Server code:
Meteor.publish('users', function() {
return Meteor.users.find({}, {fields: {username: 1, emails: 1, profile: 1, roles: 1}});
});
Meteor.publish('userProfile', function(username) {
// Try to find the user by username
var user = Meteor.users.findOne({
username: username
});
// If we can't find it, mark the subscription as ready and quit
if (!user) {
this.ready();
return;
}
// If the user we want to display the profile is the currently logged in user
if(this.userId === user._id) {
// Then we return the curresonding full document via a cursor
return Meteor.users.find(this.userId);
} else {
return Meteor.users.find(user._id, {
fields: {
profile: 0
}
});
}
});
I want to do something similar with a pages collection that I've set up. Creating the collection works and the collection page has an _id field that is made upon creation.
Right now the program works nicely for users where mysite.com/# works. Now I want the same thing to work for mysite.com/&
I've basically attempted to do the exact same thing as I did in the above code with the user name but it wasn't working. I've checked to make sure my creation of the collection items are working and they are. But somehow I can't figure out how to do this same thing with collections since I'm relatively new to using routes.
This is what I've attempted:
Here's my routes:
var pageRoute = '/&:_id';
Router.route(pageRoute, {
name: 'page',
controller: 'PageController'
});
PageController = RouteController.extend({
template: 'page',
waitOn: function() {
return Meteor.subscribe('Page', this.params._id);
},
data: function() {
var _id = Router.current().params._id;
return Meteor.pages.findOne({
_id: _id
});
}
});
Server code:
Meteor.publish('pages', function() {
return Pages.find({});
});
Meteor.publish('Page', function(_id) {
// Try find the page by _id
var page = Meteor.pages.findOne({
_id: _id
});
// If we can't find it, mark the subscription as ready and quit
if (!page) {
this.ready();
return;
}
// If the page we want to display is not claimed, display it
if(true) {
return Meteor.pages.find(this._id);
} else {
// Redirect to the page
}
});
The Schema of the Page Collection:
_id: ,
createdAt: ,
CreatedBy: ,
claimedAt: ,
claimedBy: ,
Update:
I've scoped it down to this problem, I get the following error in the console server-side:
I20160202-11:16:24.644(2)? Exception from sub qrPage id 2kY6RKCTuCpBDbuzm TypeError: Cannot call method 'findOne' of undefined
I20160202-11:16:24.645(2)? at [object Object].process.env.MAIL_URL [as _handler] (server/ecclesia.life_server.js:40:33)
I20160202-11:16:24.645(2)? at maybeAuditArgumentChecks (livedata_server.js:1698:12)
I20160202-11:16:24.645(2)? at [object Object]._.extend._runHandler (livedata_server.js:1023:17)
I20160202-11:16:24.645(2)? at [object Object]._.extend._startSubscription (livedata_server.js:842:9)
I20160202-11:16:24.646(2)? at [object Object]._.extend.protocol_handlers.sub (livedata_server.js:614:12)
I20160202-11:16:24.646(2)? at livedata_server.js:548:43
This error occurs whenever I try to direct to mysite.com/&<_id>
Based on this website: https://perishablepress.com/stop-using-unsafe-characters-in-urls/
It looks like # is considered an unsafe character to use in a URL string. On the web page above, it looks like there are several symbols you could use instead as safe characters.
I just tried this on my own machine, and I don't think Meteor plays nicely when the # is introduced in the URL.
This got it working...
Publications:
Meteor.publish('qrpages', function() {
return QRPages.find({});
});
Meteor.publish('qrPage', function(id) {
// Try find the qrpage by _id
var qrpage = QRPages.find({_id: id});
// If we can't find it, mark the subscription as ready and quit
if (!qrpage) {
this.ready();
return;
}
return qrpage;
});
Routes:
var qrpageRoute = '/$:_id';
Router.route(qrpageRoute, {
name: 'qrpage',
controller: 'QRController'
});
QRController = RouteController.extend({
template: 'qrpage',
waitOn: function() {
var id = this.params._id;
return Meteor.subscribe('qrPage', id);
},
data: function() {
var id = this.params._id;
return QRPages.findOne({
_id: id
});
}
});
For example, I have a Posts collection, which has userId indicates this post belongs to whom.
And I have a route like this:
Router.route('/:username/posts', {
waitOn: function(){
return Meteor.subscribe('posts', username); // A
// var user = Meteor.users.find({username: username}); //B
// if(user) {
// return Meteor.subscribe('posts', user._id);
// } else {
// return null; // ???
// }
}
});
And publish
Meteor.publish("posts", function(userId){ // C
check(userId, String);
return Posts.find({userId: userId});
});
Meteor.publish("posts", function(username){ // D
check(username, String);
if(user) {
return Posts.find({userId: user._id});
} else {
return null; // ???
}
});
I'm confused how to handle like GET /notexistusername/posts ??
You can configure a notFoundTemplate for iron-router either globally or on a per-route basis.
Globally:
Router.configure({
layoutTemplate: 'layout',
notFoundTemplate: 'notFound',
loadingTemplate: 'loading'
});
In a specific route (also I've cleaned up your route code):
Router.route('/:username/posts', {
notFoundTemplate: 'notFound',
data: function(){
var userId = Meteor.users.find({ username: this.params.username })._id;
return Posts.find({ userId: userId });
},
waitOn: function(){
var userId = Meteor.users.find({ username: this.params.username })._id;
return Meteor.subscribe('posts', userId);
}
});
Your notFound template would typically be your 404 page.
Also you can simplify your publication to:
Meteor.publish("posts", function(username){
check(username, String);
return Posts.find({username: username});
});
Since if there are no matches the find will return a null cursor and that will tell the route there's no data.
I have the following meteor method
hasNoPendingPayments: function() {
var userId = Meteor.userId();
console.log(userId); <---------------------- correctly logs userId
var user = Users.findOne({_id: userId }, { fields: { services: 0 } });
console.log(user); <-------------------------- logs 'undefined'
return hasNoPendingPayments(user);
},
This private helper I call from the above
hasNoPendingPayments = function(user) {
// console.log('hasNoPendingPayments ');
// console.log(user);
var payments = Payments.find({ userId: user._id, status: {
$in: [Payments.States.PENDING, Payments.States.PROCESSING]}
});
return payments.count() === 0;
};
And I call it from the client here
Template.payments.created = function() {
this.hasNoPendingPayments = new ReactiveVar(false);v
};
Template.payments.rendered = function () {
Session.set('showPaymentRequestForm', false);
var self = this;
Meteor.call('hasNoPendingPayments', function(error, result) {
if (result === true) { self.hasNoPendingPayments.set(true); }
});
...
However, I get an undefined error on the server when I load the template initially (I marked where in code). Although, when I try call the same query on the client with the same userId, i correctly gets the user record
Any idea as to why this is?
Try with this.
Template.payments.rendered = function () {
Session.set('showPaymentRequestForm', false);
var self = this;
if(Meteor.userId()){
Meteor.call('hasNoPendingPayments', function(error, result) {
if (result === true) { self.hasNoPendingPayments.set(true); }
});
}else{
console.log("Seems like user its not logged in at the moment")
}
Maybe when you make the Meteor.call, the data its not ready
Also just to be sure, when you run Users.findOne({_id: userId }, { fields: { services: 0 } }); on console.log what you get?
Maybe the find is wrong or have some typo
update
Router.map(function()
{
this.route('payments',
{
action: function()
{
if (Meteor.userId())
this.render();
} else{
this.render('login') // we send the user to login Template
}
}
}
or waitOn
Router.map(function () {
this.route('payments', {
path: '/payments',
waitOn: function(){
return Meteor.subscribe("userData"); //here we render template until the subscribe its ready
}
});
});
Meteor stores all the user records in Meteor.users collection
so try Meteor.users.findOne({_id: userId }....)
Instead of Users.findOne({_id: userId }, { fields: { services: 0 } });
in your server method
I am using Meteor 0.8 and iron-router.
I have a single route that I use to subscribe to a number of collections. What I would like to do is create a document when you arrive on the route and then subscribe to it so I can access it.
This is my route:
this.route('product_collection', {
path: '/collection/:collection',
template: 'product_collection',
layoutTemplate: 'layout-new',
waitOn: function() { return [ Meteor.subscribe('specific_product_collection', this.params.collection), Meteor.subscribe('product_types')] },
data: function () { return ProductCollections.findOne({ url: this.params.collection }) },
onBeforeAction: function(pause){
//Prevent double rendering
if (this.ready()) {
var productType = ProductTypes.findOne({url: this.params.collection })
console.log(productType)
if(productType){
var product = {
productType: productType._id
};
Session.set("productTypeId", productType._id);
Products.insert(product, function(error, id) {
if (error) {
console.error(error);
set_notification('Oops, something went wrong.', 'Please try again later.');
} else {
Session.set("productId", id);
Session.set("productName", productType.name );
//Not working
Meteor.subscribe('specific-product', id);
console.log('should be subscribed')
}
});
}
} else {
console.log('loading')
this.render('loading');
pause();
}
},
});
Ok,
I found out the ID was different on the server vs client side location. So ended up writing a meteor method call on the server.
See reference: Retrieve _id after insert in a Meteor.method call