Use this.userId in publish functions - meteor

This Meteor server code is giving the error below:
Meteor.publish('myCol', function (age) {
if (!this.userId) return;
if (Meteor.user().profile.hasOwnProperty('gotNoAge')) return; //<=== error line
console.log('publishing for age: ' + age);
return MyCol.find({age: age}, {
fields: {
myField: true
}, limit: 1
});
});
Error: Meteor.userId can only be invoked in method calls. Use this.userId in publish functions.
I tried changing the "error line" to the following for no avail.
if (Meteor.users.find({_id:this.userId}).profile.hasOwnProperty('gotNoAge')) return;
Any suggestins? thx

Try the following code
Meteor.publish('myCol', function (age) {
if (!this.userId) return;
var user = Meteor.users.findOne({_id: this.userId});
if (user.profile.hasOwnProperty('gotNoAge')) return;
console.log('publishing for age: ' + age);
return MyCol.find({age: age}, {
fields: {
myField: true
}, limit: 1
});
});

Related

Meteor - Iron router: redirect on invalid parameter

I have the following route:
Router.route('publication/:_id', {
name: 'show_publication',
controller: 'PublicationController',
action: 'show',
where: 'client',
waitOn: function() {
return [
Meteor.subscribe("publication", new Mongo.ObjectID(this.params._id)),
Meteor.subscribe("deal", new Mongo.ObjectID(this.params._id))
];
}
});
And the following controller action:
// ...
show: function() {
var publication = Publications.findOne({
_id: new Mongo.ObjectID(this.params._id)
});
if (publication) {
this.render('Publication', {
data: publication
});
//The hex string is valid but it's not a publication _id
} else {
Router.go('home');
}
}
// ...
The _id parameter is an hex string and with that I create an ObjectID to retrive a publication.
The problem comes when the parameter is not a correct hex string. I get this error in the console:
Exception in callback of async function: Error: Invalid hexadecimal string for creating an ObjectID
So, before calling the waitOn function I would like to check if the hex string is valid and, if it is not, redirect to the home page. I tried to use onBeforeAction:
// ...
onBeforeAction: function() {
try {
new Mongo.ObjectID(this.params._id);
} catch (e) {
Router.go('home');
}
}
// ...
But it didn't work.
Any ideas?
onBeforeAction: function() {
try {
new Mongo.ObjectID(this.params._id);
} catch (e) {
Router.go('home');
}
}
instead of "onBeforeAction:" write the above code in "data:" callback, as your waitOn function waits till data returned
data: function() {
try {
new Mongo.ObjectID(this.params._id);
} catch (e) {
Router.go('home');
}
}

Weird undefined error on server

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

Using Jasmine, how can I test the returned value of asynchronized call?

I am using jasmine to test the features of redis. As the redis APIs are all asynchronized call, I don't know how to test the result with jasmine expect().toBe(). I always see the error:
throw err;
^
TypeError: Cannot call method 'expect' of null
Here is my test code:
var redis = require('redis');
describe("A suite for redis", function() {
var db = null;
beforeEach(function() {
db = redis.createClient();
// if you'd like to select database 3, instead of 0 (default), call
// db.select(3, function() { /* ... */ });
db.on("error", function (err) {
console.log("Error " + err);
});
});
afterEach(function() {
db.quit();
});
it('test string', function(){
db.set('str_key1', 'hello', redis.print);
db.get('str_key1', function(err,ret){
expect(ret).toBe('hello');
});
});
});
For synchronized call, may use Jasmine asynchronous feature, passing a done() to beforeEach() and it(), see:
http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support
So, your code can be changed to:
var redis = require('redis');
describe("A suite for redis", function() {
var db = null;
beforeEach(function(done) {
db = redis.createClient();
// if you'd like to select database 3, instead of 0 (default), call
// db.select(3, function() { /* ... */ });
db.on("error", function (err) {
console.log("Error " + err);
});
done();
});
afterEach(function(done) {
db.quit();
done();
});
it('test string', function(done){
db.set('str_key1', 'hello', redis.print);
db.get('str_key1', function(err,ret){
expect(ret).toBe('hello');
done(); // put done() after expect(), or else expect() may report error
});
});
});
expect(val).toBe('hello');
I don't see "val" is defined in above code, you may want to check "ret".
expect(ret).toBe('hello');

Meteor method not returning ID to client

I am in the process of integrating stripe payments on my website, but I have run into a problem.
I want to transition the user to a dynamic route upon submitting the payments form (iframe supplied by stripe), but the Meteor method that I call on the client returns undefined instead of the ID of the newly inserted document that I wish to transition to
Any advice?
ERROR
Error: Missing required parameters on path "/purchases/:purchaseId". The missing params are: ["purchaseId"]. The params object passed in was: undefined.
client:
Template.viewTab.events({
'click #download': function(event) {
handler.open({
name: 'Tabr',
description: this.title,
amount: this.price
});
event.preventDefault();
},
});
var handler = StripeCheckout.configure({
key: '..............',
token: function(token) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
tabId = Tabs.findOne()._id;
Meteor.call('makePurchase', tabId, token, function(error, purchaseId) {
if (error) {
console.log('makePurchaseError: ' + error);
FlashMessages.clear();
return FlashMessages.sendError(error.message, {
autoHide: true,
hideDelay: 10000
});
}
console.log(purchaseId);
Router.go('viewPurchase', purchaseId);
});
}
});
Server:
Meteor.methods({
/**
* [makePurchase attempts to charge the customer's credit card, and if succesful
* it inserts a new purchaes document in the database]
*
* #return {[String]} [purchaseId]
*/
makePurchase: function(tabId, token) {
check(tabId, String);
tab = Tabs.findOne(tabId);
Stripe.charges.create({
amount: tab.price,
currency: "USD",
card: token.id
}, Meteor.bindEnvironment(function (error, result) {
if (error) {
console.log('makePurchaseError: ' + error);
return error;
}
purchaseId = Purchases.insert({
sellerId: tab.userId,
tabId: tab._id,
price: tab.price
}, function(error, result) {
if (error) {
console.log('InsertionError: ' + error);
return error;
}
return result;
});
}));
console.log(purchaseId);
return purchaseId;
}
});

Cannot call method 'create' of undefined

Here is what I'm getting from the console server side.
I20140516-21:27:12.142(0)? There was an error on this page. Cannot call method 'create' of undefined
I am not finding a good reason why this method isn't defined. I have the balanced-payments-production package from Atmosphere loaded and this includes the balanced.js file and the api export to the server. Any help here is appreciated.
Here is my events.js file
Template.CheckFormSubmit.events({
'submit form': function (e, tmpl) {
e.preventDefault();
var recurringStatus = $(e.target).find('[name=is_recurring]').is(':checked');
var checkForm = {
name: $(e.target).find('[name=name]').val(),
account_number: $(e.target).find('[name=account_number]').val(),
routing_number: $(e.target).find('[name=routing_number]').val(),
recurring: { is_recurring: recurringStatus },
created_at: new Date
}
checkForm._id = Donations.insert(checkForm);
Meteor.call("addCustomer", checkForm, function(error, result) {
console.log(error);
console.log(result);
// Successful tokenization
if(result.status_code === 201 && result.href) {
// Send to your backend
jQuery.post(responseTarget, {
uri: result.href
}, function(r) {
// Check your backend result
if(r.status === 201) {
// Your successful logic here from backend
} else {
// Your failure logic here from backend
}
});
} else {
// Failed to tokenize, your error logic here
}
// Debuging, just displays the tokenization result in a pretty div
$('#response .panel-body pre').html(JSON.stringify(result, false, 4));
$('#response').slideDown(300);
});
var form = tmpl.find('form');
//form.reset();
//Will need to add route to receipt page here.
//Something like this maybe - Router.go('receiptPage', checkForm);
},
'click [name=is_recurring]': function (e, tmpl) {
var id = this._id;
console.log($id);
var isRecuring = tmpl.find('input').checked;
Donations.update({_id: id}, {
$set: { 'recurring.is_recurring': true }
});
}
});
Here is my Methods.js file
function getCustomer(req, callback) {
try {
balanced.marketplace.customers.create(req, callback);
console.log(req.links.customers.bank_accounts);
}
catch (error){
var error = "There was an error on this page. " + error.message;
console.log(error);
}
}
var wrappedGetCustomer = Meteor._wrapAsync(getCustomer);
Meteor.methods({
addCustomer: function(formData) {
try {
console.log(formData);
return wrappedGetCustomer(formData);
}
catch (error) {
var error = "There was an error on this page." + error.message;
console.log(error);
}
}
});
I needed to run balanced.configure('APIKEYHERE'); first, then run the balanced code.

Resources