Iron router: call to Meteor.user() from router controller returns error - meteor

In Iron router path controller I'm trying to load different templates depending on user login status like this:
Router.map(function() {
this.route('start', {
path: '/',
controller: StartController
});
})
StartController = RouteController.extend({
template: Meteor.user() ? 'home' : 'landing',
waitOn: function() {
return [Meteor.subscribe('something')]
}
});
However I get exception in console:
"...Error: Meteor.userId can only be invoked in method calls. Use this.userId in publish functions..."
I don't really understand what that error means, and what Am I doing wrong here.

The code you've posted is executed on the server. On the server, Meteor.user() can only be executed in methods.
However, even if this error wouldn't exist, your code wouldn't function as you wish anyway. Meteor.user() ? 'home' : 'landing' will be executed once in the beginning (when the user probably isn't logged in), and won't be re-executed when the user signs in/out.
Read this in the docs, which is kind of doing what you want.

Related

Meteor audit-argument-checks

I have a Meteor project where I'm using audit-argument-check. I'm getting an error message
Error: Did not check() all arguments during publisher 'document
I'm know this is related the audit-argument-check not being able to check all arguments. But as far as I'm concerned, I checked all of them. Concrete, I have defined a collection 'documents' and attached a SimpleSchema. As part of iron-router, I have the following:
Router.route('customerDocumentShow', {
template: 'customerDocumentShow',
path: 'customer/documents/:_id',
waitOn: function () {
return Meteor.subscribe('document', this.params._id);
},
data: function () {
return Documents.findOne(this.params._id);
}
});
So I'm passing only the documentId (this.params._id). On the server, I have defined a method:
Meteor.methods({
documentsReadMethod: function(documentId){
check(documentId, String);
var documentItem = Document.findOne(argument);
if (!documentItem) {
throw new Meteor.Error(500, 'Error 500: Not Found', 'No documents found.');
}
return documentItem;
}
});
So I'm checking to documentId in the server method. So not sure why I'm getting this error message.
Note: One thing I'm not entirely sure about though is how I need to call this method (right now, it's documentsReadMethod_. I'm not explicitly calling (on the client):
Meteor.call(documentsReadMethod, this.params_id);
as I'm using autoform, collection2 and simpleschema. I've been spending the entire weekend, but have no clue. Any idea's ?
Note: the code is on github: https://github.com/wymedia/meteor-starter-base
The problem is in the publish. You didn't check the id here:
https://github.com/wymedia/meteor-starter-base/blob/master/server/publications/documents.js#L16
Just add check(id, String); line 16 and it should work.
I have the same problem with another tuto !
Answer found at check is not defined in meteor.js : since Meteor v1.2, you have to add this package:
$ meteor add check

Iron Router: How to Provide Same Data to Multiple Routes

It's evident how to provide route-specific data, i.e. through the use of a controller:
PostController = RouteController.extend({
layoutTemplate: 'PostLayout',
template: 'Post',
waitOn: function () { return Meteor.subscribe('post', this.params._id); },
data: function () { return Posts.findOne({_id: this.params._id}) },
action: function () {
this.render();
}
});
But how does one provide data for the application in general? In the case that every route needs to be subscribed to the same subset of information, so that the pub/sub doesn't need to be re-done on every route change. Thanks!
It sounds to me like you are looking for a completely general publication/subscription scheme so that you do not have to define the waitOn/data option combination for every single route or route controller that you define. In that case, you can simply publish a given set of data on the server like so:
Meteor.publish('someData', function() {
return SomeDataCollection.find({});
});
and subscribe to that set of data on the client like so:
Meteor.subscribe('someData');
With this publication/subscription pair setup, you will have access to the data provided in all routes. You just have to make sure that you check for non-existent data in your code to handle the first load of any given template when the data has not been loaded on the client yet. In this manner, you would never have to actually define a the waitOn and data options for any route or route controller.
If you would like to utilize Iron Router in a different way than through route controllers, you also have the option of waiting on one/many subscriptions globally by using the Router.configure({}); function. To use the example above:
Router.configure({
waitOn: function() {
return Meteor.subscribe('someData');
}
});
For information about this route option and all of the other options that you have available at a global level, check this out.

Meteor Blaze error with Template Helper

Most of my template helpers result in blaze errors and I'm not sure why. What makes them more strange is that they do not block rendering or events from the templates at all, in fact, the app works fine.
The main issue is a messy, messy, console. An example of this is below:
Template.templatename.helpers({
adminhelper: function(){
var theUser = Meteor.user(),
theUserId = theUser['_id'];
if(theUserId == "XXX"){
return true;
}
}
});
Just one way of checking which user is an admin user. This results in:
Exception in template helper: TypeError: Cannot read property '_id' of undefined
at Object.Template.templatename.helpers.adminhelper (http://localhost:3000/client/lib/helpers.js?37db222f849959237e4f36abdd8eba8f4157bd32:5:23)
at http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:2693:16
at http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:1602:16
at Object.Spacebars.call (http://localhost:3000/packages/spacebars.js?3c496d2950151d744a8574297b46d2763a123bdf:169:18)
at Template.manage.Blaze.If.HTML.HEADER.HTML.DIV.class (http://localhost:3000/client/views/template.templatename.js?868248757c652b031f64adad0edec9e2a276b925:6:22)
at null.<anonymous> (http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:2454:44)
at http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:1795:16
at Object.Blaze._withCurrentView (http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:2029:12)
at viewAutorun (http://localhost:3000/packages/blaze.js?77c0809654ee3a10dcd5a4f961fb1437e7957d33:1794:18)
at Tracker.Computation._compute (http://localhost:3000/packages/tracker.js?192a05cc46b867dadbe8bf90dd961f6f8fd1574f:288:36)
Interestingly, client/views/template.templatename.js does not exist. I put all helpers in a helpers.js file, and all events in an events.js file.
For my route I have
Router.route('/theurl',function(){
this.render('templatename');
},{
waitOn: function(){
return Meteor.user();
}
});
What can I do to avoid these issues in the future?
Just use a guard to check for the existence of Meteor.user() before extracting the _id. Waiting on Meteor.user() in the route doesn't work, as waitOn requires a subscription. Alternatively you can just do this:
Template.templatename.helpers({
adminhelper: function() {
return Meteor.userId() === 'XXX';
}
});
An even better solution is to use the roles package.

Force iron-router to go to current route

I have created a route like:
this.route('design.create', {
path: '/design',
template: 'Design',
I have wroten some waitOn, data, onBeforeAction, onStop related and executed when the route is loaded.
I have a "strange" use case:
Where I'm already in the route design.create I would like re-init it (execute again waitOn, data, onBeforeAction, onStop).
A simple: Router.go('design.create') not works...I guess because I'm already on the same route.
Seems that:
Router.current()._computation.invalidate()
Do what I want...but it's not very elegant call a private method
Set a dependency by using a session variable in the onBeforeAction and change the session variable when you what the current route to get rerun:
...
onBeforeAction: function() {
Session.get('dependOnMe')
// the acutal onBeforeAction-code goes here
}
...
...
// somewhere else
Session.set('dependOnMe', new Date())
// will trigger the onBeforeAction again
...

trying to use params on main route (/) of my meteor app

I'm trying to use params on my main route. But in fact the params are not set and they are used in the path :
Router.map(function funcClientRouterMap(){
this.route('home', {
path: '/:_redirect?',
action: function funcClientRouterMapAction(){
console.log(this.path, this.params);
}
})
});
now if i try manual redirection here is what i get :
Router.go('home'); // it redirects on / => ok
Router.go('home', {_redirect: test}); // this.path = /test, and this.params is empty
How can i use _redirect like a params and not a route ?
Thanks
Router.go accepts a path as its first argument (per the docs). So if you were trying to programmatically cause the same result as the user going to /redirectMeSomewhere, you just use:
Router.go('/redirectMeSomewhere');
And this.params._redirect should be 'redirectMeSomewhere'.
Note that like #apendua implies, if you have other routes it could cause chaos to have a route defined as /:anything, because the other routes may never get triggered. If the above doesn't do the trick, try commenting out all your other routes to see if that changes anything.

Resources