Step 8

Adding user model

Over the next steps, we are going to be adding users and authentication.

Let's first create our User model.

npm i -S bcrypt

Bcrypt is a library that we will use to hash our users' passwords.

src/models/user.js

const bcrypt = require('bcrypt');
const sequelize = require('./sequelize');

const User = sequelize.define(
	'User',
	{
		username: sequelize.Sequelize.STRING,
		password: sequelize.Sequelize.STRING
	},
	{
		hooks: {
			beforeSave: async function(user) {
				try {
					if (user.changed('password')) {
						const salt = await bcrypt.genSalt(10);
						const hash = await bcrypt.hash(user.password, salt);
						user.password = hash;
					}
				} catch (error) {
					console.error('Error hashing user password');
					throw error;
				}
			}
		},
		defaultScope: {
			attributes: { exclude: ['password'] }
		},
		scopes: {
			withPassword: {
				attributes: {}
			}
		}
	}
);

User.prototype.comparePassword = function(password) {
	return password && bcrypt.compareSync(password, this.password);
};

User.prototype.toJSON = function() {
	const values = Object.assign({}, this.get());

	delete values.password;
	return values;
};

module.exports = User;

Here, we are creating a User model with 2 fields, username and password. With sequelize, you can add "hooks", where you can execute some logic at a certain point in time of program execution relating to a specific model. Here, we add a beforeSave hook to our model, which hashes the user's password before it saves to the database. Next, we add some scopes to our model. Scopes allow you to modify queries based on a certain scope. By default, we exclude the password because we do not want to leak that information to the public, but if we need to fetch a user's password, we can pass the "withPassword" scope into our query and we will receive the user's password. Finally, we add an instance method for each instance of our model to help compare a user's password with one received from an HTTP request.

Let's add our migrations and seeders

src/migrations/create-user.js

'use strict';
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('Users', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      username: {
        type: Sequelize.STRING
      },
      password: {
        type: Sequelize.STRING
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.dropTable('Users');
  }
};

src/seeders/users.js

'use strict';
const bcrypt = require('bcrypt');

module.exports = {
	up: (queryInterface, Sequelize) => {
		/*
			Add altering commands here.
			Return a promise to correctly handle asynchronicity.

			Example:
			return queryInterface.bulkInsert('People', [{
				name: 'John Doe',
				isBetaMember: false
			}], {});
		*/

		return queryInterface.bulkInsert(
			'Users',
			[
				{
					username: 'Ross Geller',
					password: bcrypt.hashSync('Ross123', bcrypt.genSaltSync(10)),
					createdAt: new Date(),
					updatedAt: new Date()
				},
				{
					username: 'Rachel Green',
					password: bcrypt.hashSync('Rachel123', bcrypt.genSaltSync(10)),
					createdAt: new Date(),
					updatedAt: new Date()
				},
				{
					username: 'Monica Geller',
					password: bcrypt.hashSync('Monica123', bcrypt.genSaltSync(10)),
					createdAt: new Date(),
					updatedAt: new Date()
				}
			],
			{}
		);
	},

	down: (queryInterface, Sequelize) => {
		/*
			Add reverting commands here.
			Return a promise to correctly handle asynchronicity.

			Example:
			return queryInterface.bulkDelete('People', null, {});
		*/
		return queryInterface.bulkDelete('Users', null, {});
	}
};

This will create our Users table in the database and populate it with 3 users when we run the command:

$ npm run initialize

Last updated

Was this helpful?