TypeError无法将属性'firstName'设置为null

时间:2019-10-23 11:12:06

标签: node.js mongodb express passport.js ejs

我知道也有类似的问题,但是我无法为我的问题找到解决方案。

我正在尝试创建一个用户个人资料页面,用户可以在其中通过使用POST请求的表单来更改其信息。但是,当在输入字段中输入值时,它将返回null。读取用于验证用户身份的输入数据时,我没有这个问题。

还可以找到用户,但是req.body返回一个空对象。

使用的工具:

  • Node.js v10.16.3
  • Express v4.17.1
  • ejs v2.7.1
  • 快速会话v1.16.2
  • 护照v ^ 0.4.0
  • cookie解析器1.4.4
  • body-parser v1.19.0

找到的用户:

{ _id: 5daf5ef80fb0d909e099d211,
  username: 'assa',
  email: 'easy@gmail.com',
  password:
   '$2b$05$A81bqD56TDmNoWhiHJVwR.2L7iqZBrRwYu1FEe/bp0TlkTMEUREvS',
  firstName: 'test',
  __v: 0 }

app.js:

let express = require("express"),
    app = express(),
    bodyParser = require("body-parser"),
    cookieParser = require('cookie-parser'),
    session = require("express-session"),
    mongoose = require("mongoose"),
    passport = require("passport"),
    flash = require('connect-flash'),
    validator = require('express-validator'),
    LocalStrategy = require("passport-local"),
    MongoStore = require('connect-mongo')(session);

let indexRoutes = require('./routes/index');
let userRoutes = require('./routes/user');
let User = require("./models/user");

// APP CONFIGURATION
mongoose.connect("mongodb://localhost:27017/test", { useNewUrlParser: true, useUnifiedTopology: true, }).then(() => {
    console.log("Connected to MongoDB");
}).catch((error) => {
    console.log("Something is wrong...");
});

require('./config/passport');

// View engine setup
app.set("view engine", "ejs");
app.use(express.static(__dirname + "/public"));

// Initial setup
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(validator());

// Session setup
app.use(cookieParser());
app.use(session({
    secret: 'somesecretforbytox',
    resave: false,
    saveUninitialized: false
}));
app.use(flash());

// Initialize passport
app.use(passport.initialize());
app.use(passport.session());

app.use(function (req, res, next) {
    res.locals.currentUser = req.user;
    res.locals.session = req.session;
    next();
});

// ======================
// Connect to route files
// ======================
app.use('/user', userRoutes);
app.use(indexRoutes);

app.listen(3033, function () {
    console.log("Listening at port 3033...");
});

user.js

let express = require('express'),
    router = express.Router(),
    passport = require('passport');

let User = require("../models/user");

// user profile
router.get("/profile", isLoggedIn, function (req, res) {
    res.render("user/profile", { currentUser: req.user });
});

router.post('/profile', (req, res) => {
    updateRecord(req, res);
    res.redirect('/user/profile');
});

function updateRecord(req, res) {
    User.findOne({ 'id': req.user.id }, function (err, user) {
        let firstName = req.body.firstName;
        user.firstName = firstName;

        user.save(function (err, doc) {
            if (err) {
                return done(err);
            }
            return done(null, doc);
        });
    });
}

router.get("/profile/edit", isLoggedIn, function (req, res) {
     res.render("user/edit", { currentUser: req.user });

});

// ...sign in and signup routes

module.exports = router;

// middleware
function isLoggedIn(req, res, next) {
    if (req.isAuthenticated()) {
        return next();
    }
    res.redirect('/user/login');
}

profile.ejs:

<form action="/user/profile" method="POST" class="form-validate form-horizontal">
    <fieldset>
        <legend>Edit addresss</legend>
        <!-- email -->
        <div class="control-group">
            <div class="control-label">
                <label id="jform_email1-lbl" for="jform_email" class="hasPopover required" title="" data-content="Въведете имейл адрес." data-original-title="Email Address">
                    Email<span class="star">&nbsp;*</span></label>
            </div>
            <div class="controls">
                <input type="email" name="email" class="validate-email required" id="jform_email" value="<%= (typeof currentUser.email != 'undefined' ? currentUser.email : '') %>" size="30" autocomplete="email" required aria-required="true">
            </div>
        </div>
        <!-- name -->
        <div class="control-group">
            <div class="control-label">
                <label id="jform_fname-lbl" for="jform_fname" class="hasPopover required" title="" data-content="Въведете име." data-original-title="Name">
                    Name<span class="star">&nbsp;*</span></label>
            </div>
            <div class="controls">
                <input type="text" name="firstName" id="jform_fname" value="<%= (typeof currentUser.firstName != 'undefined' ? currentUser.firstName : '') %>" class="required" size="30" required aria-required="true">
            </div>
        </div>
    </fieldset>

    <div class="form-actions">
        <!-- <input type="hidden" name="_csrf" value=" csrfToken "> -->
        <button type="submit" class="btn btn-primary validate">
            <span>Save</span>
        </button>
        <!-- <input type="hidden" name="_csrf" value=" csrfToken "> -->
        <a class="btn" href="/" title="Cancel">Cancel</a>
    </div>
</form>

用户架构:

let mongoose = require('mongoose');
let Schema = mongoose.Schema;
let bcrypt = require('bcrypt');

let userSchema = new Schema({
  username: { type: String, required: true },
  email: { type: String, required: true },
  password: { type: String, required: true },
  firstName: { type: String },
  lastName: { type: String },
  address: { type: String },
  zip: { type: String },
  country: { type: String },
  phone: { type: String }
});

userSchema.methods.encryptPassword = function (password) {
  return bcrypt.hashSync(password, bcrypt.genSaltSync(5), null);
};

userSchema.methods.validPassword = function (password) {
  return bcrypt.compareSync(password, this.password);
}

module.exports = mongoose.model('user', userSchema);

2 个答案:

答案 0 :(得分:1)

按照Subburaj和Matheus Hatje的建议将查询更改为User.findOne({ '_id': req.user.id }即可解决问题。

答案 1 :(得分:0)

快照

router.post('/profile', (req, res) => {
    ModelName.create(req.body).then(result => {
                     if(result){
                          res.redirect('/user/profile');
                     }).catch(err){
                     res.send(err)
                    }  
    });                                                                                     

创建函数单独编写,请勿与更新函数进行比较。