Reputation: 453
I'm just trying to verify if an Account exists with a particular email, however I learned that Accounts.findUserByEmail()
only works server-side.
It would appear the repeatedly-suggested way would be to define a Meteor.method()
and do all the work in there. Unfortunately I apparently have no idea what I'm doing because I'm getting an error that no one else has been getting.
component.js:
Meteor.call('confirm', email);
methods.js:
Meteor.methods({
'confirm': (email) => {
if (Accounts.findUserByEmail(email)) {
return;
}
}
});
All I get is this error:
Exception while simulating the effect of invoking 'confirm' TypeError: Accounts.findUserByEmail is not a function
Am I completely misunderstanding the dynamic of Meteor.methods + Meteor.call? Is it not actually server-side??
Currently using Meteor package, [email protected]
Upvotes: 2
Views: 901
Reputation: 16478
If your client-side code includes a method definition, it is treated as a stub, which means that it is run in a special mode that provides "optimistic UI" and its effects on data are undone once the actual server method returns its response to the client.
It could be worthwhile to implement different versions of (at least some of the) methods for the client and server, and to avoid including some of them on the client altogether.
If you choose to use the same function on both the client and the server, there are Meteor.isServer
, Meteor.isClient
and this.isSimulation
(the latter is specifically for the methods), that allow you to execute some of the blocks only on the client/server.
Note that the code in your question does not do what you expect it to, and you do not check the method argument.
For this specific use case, you should probably only implement the method on the server (simply don't import its code in your client build):
Meteor.methods({
isEmailInSystem(email) {
check(email, String);
return !!Accounts.findUserByEmail(email);
}
});
You can read more about the method lifecycle in The Meteor Guide.
From the guide (gist, some details omitted):
Method simulation runs on the client - If we defined this Method in client and server code, as all Methods should be, a Method simulation is executed in the client that called it.
The client enters a special mode where it tracks all changes made to client-side collections, so that they can be rolled back later. When this step is complete, the user of your app sees their UI update instantly with the new content of the client-side database, but the server hasn’t received any data yet.
- A method DDP message is sent to the server
- Method runs on the server
- Return value is sent to the client
- Any DDP publications affected by the Method are updated
updated
message sent to the client, data replaced with server result, Method callback fires
After the relevant data updates have been sent to the correct client, the server sends back the last message in the Method life cycle - the DDP updated message with the relevant Method ID. The client rolls back any changes to client side data made in the Method simulation in step 1, and replaces them with the actual changes sent from the server in step 5.Lastly, the callback passed to Meteor.call actually fires with the return value from step 4. It’s important that the callback waits until the client is up to date, so that your Method callback can assume that the client state reflects any changes done inside the Method.
Upvotes: 2
Reputation: 9680
Meteor simulates method calls in the front-end too by running "stubs" of your methods. The idea is to have a better user experience because the UI is updated immediately before the server has responded. However this also means that if you run server-only code in Meteor methods, you have to make sure that the code is only run on the server:
Meteor.methods({
'confirm': (email) => {
if (Meteor.isServer && Accounts.findUserByEmail(email)) {
return;
}
}
});
Alternatively, you can place the above method definition in a file that is only loaded on the server, like any file on the /server
-directory or (recommended) in /imports
to a file that is only include
d by server code. Then you shouldn't need to use Meteor.isServer
separately.
Upvotes: 3