Meteor call server method from helper

#1

I have a helper, in which i want to get the collection ‘data’, for currently logged user. I do not publish this collection because it has sensitive data, so i want to get the collection via call to server like:

server side:

export const GetData  = new ValidatedMethod({
    name: 'GetData',
    validate: new SimpleSchema({
    }).validator(),
    run() {

        var id = Meteor.userId();
        var user = Meteor.users.findOne({_id: id});
        if(user)
           return Data.find({assigned_id: user.profile.secret_id});
     
        return null;

    },
});

this way i get sensitive data only for currently logged user, so its not gonna be abused, but how to call server method from helper?

Template.pageBanks.helpers({
        data(){
             Meteor.call('GetData', function(err,data){
                   if(!err)
                       return data;
             });
        }
});

This doesn’t work, how can i call server method in helper properly?

EDIT:

I’m aware of solutions using onCreated or RactiveMethod, however they don’t fit, i want to make the helper reactive. Also i have multi user environment, users are working in the same time, so i cant store this in session ( i mean i probably could, but that’s not good practive ) so i need a solution using local reactive var for current template instance.

#2

Meteor calls are never going to be reactive. If you want reactivity, you want a publication.

Publications can be filtered to only send data for the current user, and made reactive so when that user changes, the data is automatically removed from the client:

// server
Meteor.publish('GetData', function() {
    var id = this.userId;
    var user = Meteor.users.findOne({_id: id});
    if(user)
       return Data.find({assigned_id: user.profile.secret_id});
     
    return [];
});
// client 
Template.pageBanks.onCreated(function() {
    this.subscribe('GetData');
});
Template.pageBanks.helpers({
    data() {
        return Data.find();
    }
});

If the logged in user changes, the publish function automatically re-runs and tells the client to delete the data / replace it with the new user’s data

3 Likes
#3

It is definitely possible to call a Meteor method in a helper. In my own Meteor app I’m making calls in onCreated or onRendered, and just attempted to make the same call in a helper and it works great. Though it should be said that using pub/sub will make the app reactive. You can still do robust security through publications as well.

Are you seeing any errors you can share? Or are you just not seeing any data come through via the Method?

#4

While you can call a method in a helper, you can’t return the results (which they were trying in their example).
It’s also just considered bad practice as all sorts of things can cause a helper to re-run, triggering another request to the server

1 Like
#5

There are a couple of things I can see here that may be tripping you up.

  1. You have defined GetData() as a Validated.Method. You should probably call it with GetData.call( … Args …) rather than Meteor.call(“GetData”, … Args …).

  2. My experience with using methods in helpers has usually been frustrating. In your sample code, once the method returns some data from the server, the helper has long since returned null back to the template and the data you are interested in is ignored. There are definitely ways around this using reactive vars and such like and I could show you some of the ways I have managed this if you really need the help, but like the other posters have said, the pub/sub stuff that meteor does so well is probably the best solution.

  3. There is a package called ReactiveMethod you can try. It is not perfect, but may be useful to you in this scenario.

#6

Bit late for the reply. I would do the following to achieve if you are using Blaze - use a combination of Autorun, ReactiveVar. Wrap the Meteor method in Autorun, which runs when id changes, using it onCreated. The Meteor method on its return populates a ReactiveVar, which is in turn returned by the helper function. The helper will run again as it is returning ReactiveVar and it is changed by the results of method.

1 Like
#7

Use a publication.

No. Don’t do that.

Use a publication!

Put this in a publication!

1 Like
#8

Why not? What’s the reasoning?

#9

This has been litigated elsewhere, but a side effect of rendering on the page should not be a remote procedure call. You’ll wind up with bugs like…

 1. Reactively update a list of templates since a new item was added
 2. onCreated is called for that template instance
 3. A method is called.
 4. Side effects.
 5. An item is added to the list you're reactively rendering against
 6. So go back to step 1.

There are so many posts of problems that stem from this doing business logic inside rendering code errors. It’s practically its own coding discipline. You can make error-free code with this pattern, but I’m trying to say that mature and talented developers don’t ever use this pattern. In a public forum it’s good to advocate for the very best practices, because if you just wanna write crap don’t ask anyone’s opinion!

#10

I asked for reasoning. Above is a somewhat silly list that isn’t informative to forum users hoping for real/helpful information. I am also not sure what you mean by “doing business logic inside rendering code errors”. That statement doesn’t make a lot of sense.

There are plenty “best practices” opinions regarding Meteor publications, which include limiting publications themselves in favor of simply using Meteor methods. I’ll give an example of running a method in an onCreated.

User logs into my app. Part of the login process is to fetch an inspirational quote that relates to the app’s purpose. The app only needs to fetch one random record from the quotes Collection, so once the template is created, the method call is made, and on return the quote is displayed. Works great and there are zero issues with our app operating this way.

Here’s another example. Users can invite others to their group, and when they do a tokenized url is sent to the invitee. When the invitee visits that url, I call a Meteor method inside onCreated for a template. The sole purpose of that method is to check the invite token to ensure it’s valid, not used, not expired, etc. Doing this with a publication (for one record) would be overkill and more complicated. And as with my above example, this approach works great, fast, and throws no errors.

If you have specific examples to enlighten users viewing this thread on why running a Method on template create/render, let’s hear it.