0

I am new to Node and starting with the Rocket Rides demo. The pilot sign-up works on the web app and I want to do the same for passengers on the web (whereas the demo has passenger signup on iOS). I can't understand why the req.user is maintained with the original code for pilots and not my adaptation for passengers.

I added console.log() in the GET of server/routes/pilots/pilots.js:

/**
 * GET /pilots/signup
 *
 * Display the signup form on the right step depending on the current completion.
 */
router.get('/signup', (req, res) => {
  let step = 'account';
  console.log("*** Req.user = " + req.user);
  // ...
});

and in the POST:

/**
 * POST /pilots/signup
 *
 * Create a user and update profile information during the pilot onboarding process.
 */
router.post('/signup', async (req, res, next) => {
  const body = Object.assign({}, req.body, {
    // Use `type` instead of `pilot-type` for saving to the DB.
    type: req.body['pilot-type'],
    'pilot-type': undefined,
  });

  // Check if we have a logged-in pilot
  let pilot = req.user;
  if (!pilot) {
    try {
      // Try to create and save a new pilot
      pilot = new Pilot(body);
      pilot = await pilot.save()
      // Sign in and redirect to continue the signup process
      req.logIn(pilot, err => {
        if (err) next(err);
        console.log("About to redirect with:");
        console.log(pilot);
        return res.redirect('/pilots/signup');
      });
    } catch (err) {
      // Show an error message to the user
      const errors = Object.keys(err.errors).map(field => err.errors[field].message);
      res.render('pilot-signup', { step: 'account', error: errors[0] });
    }
  } 
  else {
    // ...
  }
});

The code for passengers is similar and I include it at the bottom. The server logs for pilot sign-up show:

*** Req.user = undefined
GET /pilots/signup 200 136.726 ms - 1865
GET /stylesheets/rocketrides.css 304 0.911 ms - -
GET /javascripts/rocketrides.js 304 1.043 ms - -
GET /images/header.jpg 304 5.187 ms - -
GET /images/rocketrides.svg 304 10.075 ms - -
About to redirect with:
{
  rocket: { country: 'US' },
  type: 'individual',
  country: 'US',
  _id: 5e7e24d38794fa32032fd052,
  email: 'name@example.com',
  password: '...',
  created: 2020-03-27T16:07:47.054Z,
  __v: 0
}
POST /pilots/signup 302 116.113 ms - 72
*** Req.user = {
  rocket: { country: 'US' },
  type: 'individual',
  country: 'US',
  _id: 5e7e24d38794fa32032fd052,
  email: 'name@example.com',
  password: '...',
  created: 2020-03-27T16:07:47.054Z,
  __v: 0
}
GET /pilots/signup 200 93.455 ms - 6018

The logs for the passenger sign-up, which I customized, show:

*** Req.user = undefined
GET /passengers/signup 200 165.900 ms - 1869
GET /stylesheets/rocketrides.css 304 2.573 ms - -
GET /javascripts/rocketrides.js 304 1.161 ms - -
GET /images/header.jpg 304 4.349 ms - -
GET /images/rocketrides.svg 304 4.423 ms - -
About to redirect with:
{
  rocket: { country: 'US' },
  type: 'individual',
  _id: 5e7e259d8794fa32032fd053,
  email: 'name@example.com',
  password: '...',
  created: 2020-03-27T16:11:09.273Z,
  __v: 0
}
POST /passengers/signup 302 32.873 ms - 80
*** Req.user = undefined
GET /passengers/signup 200 137.442 ms - 1869

In both cases req.user starts with undefined, then the user (passenger or pilot) is saved to the database, and the code redirects to GET with a valid object. With pilots, that object is received by the GET request, but not for passengers.

The app already uses state session in app.js and works for one type of sign-up, so my question is different from this thread. It might be something obvious to most and buried in the code for a newbie. I also included the passport.serializeUser() from pilots.js into passengers.js.

How can I fix the problem, or debug it?

extras

The code for the GET of server/routes/passengers/passengers.js:

/**
 * GET /passengers/signup
 *
 * Display the signup form on the right step depending on the current completion.
 */
router.get('/signup', (req, res) => {
  let step = 'account';
  console.log("*** Req.user = " + req.user);
  // ...
});

The code for the POST in the same file:

/**
 * POST /passengers/signup
 *
 * Create a user and update profile information during the passenger onboarding process.
 */
router.post('/signup', async (req, res, next) => {
  const body = Object.assign({}, req.body, {
    // Use `type` instead of `passenger-type` for saving to the DB.
    type: req.body['passenger-type'],
    'passenger-type': undefined,
  });

  // Check if we have a logged-in passenger
  let passenger = req.user;
  if (!passenger) {
    try {
      // Try to create and save a new passenger
      passenger = new Passenger(body);
      passenger = await passenger.save()

      // Sign in and redirect to continue the signup process
      req.logIn(passenger, err => {
        if (err) next(err);
        console.log("About to redirect with:");
        console.log(passenger);
        return res.redirect('/passengers/signup');
      });
    } catch (err) {
      // Show an error message to the user
      const errors = Object.keys(err.errors).map(field => err.errors[field].message);
      res.render('passenger-signup', { step: 'account', error: errors[0] });
    }
  } 
  else {
    // ...
  }
});
miguelmorin
  • 5,025
  • 4
  • 29
  • 64

1 Answers1

0

I did not understand the Passport strategy, and the passenger user was being serialized and deserialized as a pilot. Only the first passport.serialize() function is valid; when I imported passengers.js first, pilots were being serialized and deserialized as passengers.

See this post for how passport works (pointed from PassportJS serializeUser and deserializeUser execution flow), and this Github issue for how to handle multiple local strategies with a single serialization and deserialization.

In my case, I will use a user class that passengers and pilots inherit from.

miguelmorin
  • 5,025
  • 4
  • 29
  • 64