I'm building a website, and i have a registration form where i need to submit a form via POST, and register a user in a mongoDB databse. The website works fine so far, but when i submit the registration form the browser just "waits for localhost" forever. I use EJS as my templating engine, although i don't think that matters.
register.ejs:
<% include partials/header %>
<%include partials/nav %>
<h1>REGISTER</h1>
Login
<form id="registerForm" action="/register" method="post">
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" name="username" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" name="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
<small id="passwordHelp" class="form-text text-muted">Your password must be at least 8 characters long.</small>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<% include partials/footer %>
app.js:
var express = require('express'),
app = express(),
mongoose = require('mongoose'),
passport = require("passport"),
bodyParser = require("body-parser"),
User = require("./models/user"),
LocalStrategy = require("passport-local"),
passportLocalMongoose = require("passport-local-mongoose");
//Set up MongoDB
var mongo = require("mongo");
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/customerapp';
//MongoJS
var mongojs = require("mongojs");
var db = mongojs("customerapp", ["users"]);
//Mongoose
var mongoose = require('mongoose');
mongoose.Promise = global.Promise
mongoose.createConnection("mongodb://localhost:27017/customerapp");
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));
app.use(require("express-session")({
secret: "wah wah wah",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
var index = require("./routes/index");
var about = require("./routes/about");
var login = require("./routes/login");
//var register = require("./routes/register");
app.all("index", index);
app.all("about", about);
app.all("login", login);
//app.all("register", register);
// AUTH Routes
//Register get request
app.get("/register", function(req, res) {
res.render("register");
});
//Handle post register req. at '/register'
app.post("/register", function(req, res) {
User.register(new User({
username: req.body.username}),
req.body.password,
function(err, user) {
if(err) {
console.log(err);
return res.render("register");
}
passport.authenticate("local")(req, res, function() {
res.redirect("/secret")
})
});
});
app.listen(process.env.PORT || 3000, process.env.IP, function () {
console.log('Example app listening on port 3000!')
})
You are using three params instead of two, use it like this.
//Handle post register req. at '/register'
app.post("/register", function(req, res) {
User.register(new User({
username: req.body.username,
password: req.body.password
}),
function(err, user) {
if(err) {
console.log(err);
return res.render("register");
}
passport.authenticate("local")(req, res, function() {
res.redirect("/secret")
})
});
});
Check to make sure your versions of mongoDB and mongoose are compatible. You can find a compatibility chart here.
In addition to checking your MongoDB and mongoose versions, you should also check if it's actually connecting to the database by using a callback function when you connect to the server, like so:
//Connecting to database using mongoose.connect with a callback
mongoose.connect("mongodb://localhost:27017/customerapp", function(error) {
if(error) {
console.log("There was an error connecting to MongoDB.");
console.log(error);
} else {
console.log("Successfully connected to MongoDB!");
}
});
This callback may also work with mongoose.createConnection instead of mongoose.connect, but I haven't tried. If neither message prints to the console, then the app is not getting any response from the server, not even an error.
For some reason, as long as mongoDB is running at all, GET requests still seem to work even if the connection attempt hangs, but POST requests run into trouble.
Source: Mongoose never connects to mongodb
Related
I am trying to build a website that allows a user to add a collectors item to the website. It has a form that requires certain fields to be filled out (I chose Funko Pop's). I have got everything working for the exception of having the image uploaded to the index.hbs page and into the MongoDB database.
Can anyone help? I think I am very close, but my terminal is throwing a Mongoose validator error (I'll show this at the end of the post)
The image seems to be sent to my "uploads" folder successfully, it just seems that there is some miscommunication happening with MongoDB because mongoose isn't happy.
Would anyone know what the issue is? And know how to fix it?
Thank you all for the help!
Here is my code:
Collection.js Controller/Route:
const express = require('express')
const router = express.Router()
const Collection = require('../models/collection')
const globalAuthFunction = require('./authenticationFunction')
const multer = require('multer')
// storage for multer
const storage = multer.diskStorage({
destination: function(err, file, callback){
callback(null, './public/uploads')
},
filename: function(req, file, callback){
callback(null, Date.now() + file.originalname)
}
})
const upload = multer({
storage: storage
})
router.get('/', (req, res) => {
Collection.find((err, collections) => {
if (err) {
console.log(err);
}
else {
res.render('collections/index', {
title: 'Collections',
collections: collections,
user: req.user
})
}
})
})
router.get('/create', globalAuthFunction.isAuthenticated, (req, res) => {
Collection.find((err, collections) => {
if(err){
console.log(err)
}
else{
res.render('collections/create', {
title: 'Add Employer',
collections: collections,
user: req.user,
})
}
})
})
router.post('/create', upload.single('image'), globalAuthFunction.isAuthenticated, (req, res) => {
Collection.create(req.body, (err, newCollection) => {
if (err) {
console.log(err)
}
else {
res.redirect('/collections')
}
})
})
router.get('/edit/:_id', globalAuthFunction.isAuthenticated, (req, res) => {
Collection.findById(req.params._id, (err, collection) => {
if(err){
console.log(err)
}
else{
res.render('collections/edit', {
title: 'Funko Pop Details',
collection: collection,
user: req.user,
image: req.file.filename
})
}
})
})
router.post('/edit/:_id', globalAuthFunction.isAuthenticated, (req, res) => {
Collection.findByIdAndUpdate({ _id: req.params._id}, req.body, null, (err, collection) =>{
if(err){
console.log(err)
}else{
res.redirect('/collections')
}
})
})
router.get('/delete/:_id', globalAuthFunction.isAuthenticated, (req, res) => {
Collection.deleteOne({ _id: req.params._id}, (err) => {
if(err){
console.log(err)
}
else{
res.redirect('/collections')
}
})
})
module.exports = router
My create.hbs:
<h1>Add a Funko Pop to Your Collection</h1>
<form method="post" enctype="multipart/form-data">
<fieldset>
<label for="character" class="col-2">Character: *</label>
<input name="character" id="character" required />
</fieldset>
<fieldset>
<label for="mediaTitle" class="col-2">Move or Television Name: *</label>
<input name="mediaTitle" id="mediaTitle" required />
</fieldset>
<fieldset>
<label for="category" class="col-2">Category: *</label>
<input name="category" id="category" required />
</fieldset>
<fieldset>
<label for="popNumber" class="col-2">Funko Pop Number: *</label>
<input name="popNumber" id="popNumber" required />
</fieldset>
<fieldset>
<label for="specialtySticker" class="col-2">Specialty Sticker: </label>
<input name="specialtySticker" id="specialtySticker" placeholder="N/A if there is no sticker"/>
</fieldset>
<fieldset>
<label for="price" class="col-2">Price: *</label>
<input name="price" id="price" required />
</fieldset>
<fieldset>
<label for="releaseYear" class="col-2">Funko Pop Release Year: *</label>
<input name="releaseYear" id="releaseYear" required />
</fieldset>
<fieldset>
<label for="image" class="col-2">Upload Image:</label>
<input type="file" name="image" id="image" value="image"/>
</fieldset>
<button class="btn btn-primary offset-2">Save</button>
</form>
My index.hbs:
<h1>Funko Pop Collection</h1>
{{#if user}}
<a class="btn btn-secondary" href="/collections/create">Add a Funko Pop</a>
{{/if}}
<section class="row">
{{#each collections}}
<div class="card col-2 m-2">
<div class="card-body text-center h-100">
<img src="{{this.image}}"/>
<h5 class="card-title">{{this.character}}</h5>
<p>Funko Pop Title: {{this.mediaTitle}}</p>
<p>Category: {{this.category}}</p>
<p>Pop Number: {{this.popNumber}}</p>
<p>Specialty Sticker: {{this.specialtySticker}}</p>
<p>Value: ${{this.price}}</p>
<p>Year:{{this.releaseYear}}</p>
{{#if ../user}}
<div>
Edit
Delete
</div>
{{/if}}
</div>
</div>
{{/each}}
</section>
My app.js:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./controllers/index');
var usersRouter = require('./controllers/users');
const collections = require('./controllers/collections')
const auth = require('./controllers/auth')
const passport = require('passport')
const session = require('express-session')
const multer = require('multer')
var app = express();
// database connection to MongoDB
if (process.env.NODE_ENV !== 'production'){
require('dotenv').config()
}
app.use(session ({
secret: process.env.PASSPORT_SECRET,
resave: true,
saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())
const User = require('./models/user')
passport.use(User.createStrategy())
// let passport read/write user data to/from session vars
passport.serializeUser(User.serializeUser())
passport.deserializeUser(User.deserializeUser())
const google = require('passport-google-oauth20').Strategy
passport.use(new google({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_CALLBACK_URL
},
(accessToken, refreshToken, profile, done) => {
User.findOrCreate({ oauthId: profile.id}, {
username: profile.displayName,
oauthProvider: 'Google',
created: Date.now()
}, (err, user) => {
return done(err, user)
})
}
))
const mongoose = require('mongoose');
const { access } = require('fs');
mongoose.connect(process.env.DATABASE_URL)
.then(
(res) => {
console.log('Connected to MongoDB')
}
).catch(() => {
console.log('Cannot connect to MongoDB')
})
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/collections', collections)
app.use('/auth', auth)
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
This is what my terminal is showing when I try and create a new Funko Pop Object in MongoDB:
It is saying there is an incorrect path or something. The image is uploading correctly to my "uploads" folder, it just seems to be having an issue with the database connection.
I thought it may be that the image type in my model was wrong, so I switched it to "Buffer" instead of "String", but it still showed me the same exact error. I have watched several tutorials, but they have set it up completely different than mine.
They seem to be using a something like this in there "post" function in there controllers:
let connection = new Connection({
title: request.body.title,
img: request.file.filename
}
I do not know enough about handlebars, MongoDB or Multer to be able to diagnose the issues that is happening. Any help would be greatly appreciated.
Thank you!
since you are using multer, change it from request.file.filename to request.file.path
This question already has answers here:
MongoDB - Error: document must have an _id before saving
(9 answers)
Closed 4 years ago.
I have a registration page that takes input username and password to store into a mongoDB.
When I click on the Register button, it loads an error page.
Which also causes a Mongoose Error in the terminal that says MongooseError: document must have an _id before saving at new MongooseError
Below are the code.
//server.js file
var express = require('express');
var app = express();
var port = 8888;
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
/*Body parser*/
app.use(bodyParser.urlencoded({
extended: true
}));
/*Database connection - MongoDB*/
//Created from the command earlier. Ensure this is done on the first_db instance
var username = 'admin';
var password = '123456';
var dbHost = 'localhost';
var dbPort = '27017';
var database = 'first_db';
var url = 'mongodb://' + username + ':' + password + '#' + dbHost + ':' + dbPort + '/' + database;
console.log('mongodb connection = ' + url);
mongoose.connect(url, function(err) {
if(err) {
console.log('connection error: ', err);
} else {
console.log('connection successful');
}
});
/***********
Declare all models here
***********/
//User model
var UserSchema = new mongoose.Schema({
_id: mongoose.Schema.ObjectId,
username: String,
password: String
});
var User = mongoose.model('user', UserSchema);
/***********
All routes go below
***********/
app.get('/', function (req, res, next){
res.sendFile( __dirname + '/index.html');
});
app.get('/register', function (req, res, next) {
res.sendFile( __dirname + '/register.html');
});
app.post('/register', function (req, res, next) {
User.create(req.body, function(err, saved) {
if(err) {
console.log(err);
res.json({ message : err });
} else {
res.json({ message : "User successfully registered!"});
}
});
});
app.listen(port, '0.0.0.0', function(){
console.log('Server running at port ' + port);
});
//register.html file
<html>
<head>
<title>My first NodeJS Website</title>
</head>
<body>
<p>Registration page</p>
<form action="/register" method="post">
<p>Username <input type="text" name="username" /></p>
<p>Password <input type="password" name="password" /></p>
<input type="submit" value="Register"/>
</form>
<p>Click here to go back. </p>
</body>
</html>
//index.html file
<html>
<head>
<title>My first NodeJS Website</title>
</head>
<body>
<p>Hello World!</p>
<form action="/login" method="post">
<p>Username <input type="text" name="username" /></p>
<p>Password <input type="password" name="password" /></p>
<input type="submit" value="Login"/>
</form>
<p>Not yet registered? Click here to create an account. </p>
</body>
</html>
You don't have to define the _id as mongoose.Schema.ObjectId in the User schema. MongoDB will implicitly generate the ID even if you don't define it in the schema and insert your object even if you don't provide value for _id. However, if you define it explicitly in the schema, Mongoose runs a validation check and expects you to provide the value - it will throw an error and your query won't even reach the database.
I am using the following stack :
React
PassportJS
NodeJS
Express and express-session
create-react-app with webpack dev server proxying API requests to my node server as mentioned in this article
When I do a form submit, I get an error Cannot POST however when I submit to the SAME url using POSTMAN or curl XPOST, I get results. Here is my server.js code :
'use strict';
const PORT = process.env.PORT || 3001;
const express = require('express');
const app = express();
const path = require('path');
const passport = require('passport')
const initPassport = require('./passport/init');
const session = require('express-session')
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser')
const configDB = require('./config/database.js');
const MongoStore = require('connect-mongo')(session);
var flash = require('connect-flash');
//Connect to mongo
mongoose.connect(configDB.url, {
useMongoClient: true
}).then(() => console.log('connection with database succeeded'))
.catch(err => console.error(err));
// Initialize Passport
initPassport(passport);
// Serve static assets
app.use(express.static(path.resolve(__dirname, '..', 'build')));
//use cookie parser to store data
app.use(cookieParser());
app.use(session({
secret: 'mysecret',
store : new MongoStore ({
db : mongoose.connection.db,
host : '127.0.0.1',
port : '27017',
url : configDB.url
}),
maxAge : 2 * 60 * 60 * 1000,
resave: false,
saveUninitialized: false
})); // session secret
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
app.post('/signup', passport.authenticate('signup', {
successRedirect: '/',
failureRedirect: '/signup'
}));
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}!`);
});
Form PAGE :
import React, { Component } from 'react';
import constants from 'constants/AuthPageConstants';
class RegisterForm extends Component {
render() {
return (
<div className="tab-pane fade in" id="basic-tab2">
<form action="/signup" method="POST">
<div className="text-center">
<div className="icon-object border-success text-success"><i className="icon-plus3"></i></div>
<h5 className="content-group">{constants.register_form_title} <small className="display-block">{constants.register_form_subtitle}</small></h5>
</div>
<div className="form-group has-feedback has-feedback-left">
<input type="text" name="username" className="form-control" placeholder={constants.register_username_placeholder} />
<div className="form-control-feedback">
<i className="icon-user-check text-muted"></i>
</div>
</div>
<div className="form-group has-feedback has-feedback-left">
<input type="password" name="password" className="form-control" placeholder={constants.register_password_placeholder} />
<div className="form-control-feedback">
<i className="icon-user-lock text-muted"></i>
</div>
</div>
<div className="form-group has-feedback has-feedback-left">
<input type="text" name="email" className="form-control" placeholder={constants.register_email_placeholder} />
<div className="form-control-feedback">
<i className="icon-mention text-muted"></i>
</div>
</div>
<div className="content-divider text-muted form-group"><span>Additions</span></div>
<div className="form-group">
<div className="checkbox">
<label>
<input type="checkbox" className="styled" />
{constants.tos_txt.substring(0, constants.tos_txt.indexOf(" "))} {constants.tos_txt.substr(constants.tos_txt.indexOf(" ") + 1)}
</label>
</div>
</div>
<button type="submit" className="btn bg-indigo-400 btn-block">Register <i className="icon-circle-right2 position-right"></i></button>
</form>
</div>
)
}
}
export default RegisterForm
Signup passport strategy
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
var bCrypt = require('bcrypt');
module.exports = function(passport){
passport.use('signup', new LocalStrategy({
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
console.log("In Signup");
findOrCreateUser = function(){
// find a user in Mongo with provided username
User.findOne({ 'username' : username }, function(err, user) {
// In case of any error, return using the done method
if (err){
console.log('Error in SignUp: '+err);
return done(err);
}
// already exists
if (user) {
console.log('User already exists with username: '+username);
return done(null, false, req.flash('message','User Already Exists'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.username = username;
newUser.password = createHash(password);
newUser.email = req.param('email');
newUser.firstName = "firstName";
newUser.lastName = "lastName";
// save the user
newUser.save(function(err) {
if (err){
console.log('Error in Saving user: '+err);
throw err;
}
console.log('User Registration succesful');
return done(null, newUser);
});
}
});
};
// Delay the execution of findOrCreateUser and execute the method
// in the next tick of the event loop
process.nextTick(findOrCreateUser);
})
);
// Generates hash using bCrypt
var createHash = function(password){
return bCrypt.hashSync(password, bCrypt.genSaltSync(10));
}
}
UPDATE
The issue appears to be due to the presence of the proxy. The form submit works if I directly call the nodejs backend API which is running on a different port (by allowing CORS) and remove the proxy. If I insert the proxy, and make the form point to the weback dev server, then form submit does not call the my nodeJS API. However, proxying works with curl and POSTMAN. Weird how curl works and form submit doesn't. Any pointers here will be helpful.
try to clear browser cache . if you are using chrome
go to settings
type cache in search
browse to bottom and clear cache .
if it doesnt solve the problem please write back
Iam not able to get the html page.My nodejs is connecting with mongodb but when iam getting values from html page the values are not storing in db.Iam not able establish the connection from frontend to db at a time.help me out
this is my login.html
<html>
<head>
<title>login</title>
</head>
<body>
<form action="/" method="POST">
<center>
User Name: <input type="text" name="username"> <br>
Password: <input type="password" name="password"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
and this is my login.js code
var express = require('express');
var app = express();
var mongoose = require('mongoose');
var url = 'mongodb://localhost:27017/logindb';
var loginSchema = mongoose.Schema({
username: String,
password: String
});
mongoose.connect(url);
app.get('/login.html', function(req, res) {
res.sendFile(__dirname + "/" + "login.html");
})
app.post('/', function(req, res) {
var Book = mongoose.model('book', loginSchema);
var book1 = new Book({
username: req.body.username,
password: req.body.password
});
book1.save(function(err) {
if (err) throw err;
console.log("Login saved succesfully");
res.end('success');
}
);
});
app.listen(8000, function() {
console.log("Server is running!");
});
For using req.body.username you need to use body-parser module,
install: npm install body-parser -S
Code:
var express = require('express'),
app = express(),
bodyparser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
In 'app.js' I have
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
'index.js' full codes
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
router.get('/', function(req, res, next) {
res.render('index', { title: 'Here' });
});
router.post('/manager', function(req, res, next) {
var connection = mysql.createConnection({
host : 'localhost',
user : req.body.username,
password : req.body.password,
database : 'shops'
});
connection.connect(function(err){
if(!err)
res.render('manager', { title: 'Here' });
else
console.log("Error connecting database ...");
});
});
module.exports = router;
In 'index.html' login form
<form id='login' method='post' action='manager'>
Username<br>
<input id='username' type='text'><br>
Password<br>
<input id='password' type='password'><br>
<input type='submit' value='Login'>
<input type='reset' value='Reset'>
</form>
In index.js line 12-13
req.body.username
req.body.password
Everytime I try to parse data from html form, they return 'undefined'. I'm new to node.js scripting. Am I doing something wrong?
You're missing name attributes on your <input> tags. Add them like:
<form id='login' method='post' action='manager'>
Username<br>
<input id='username' name='username' type='text'><br>
Password<br>
<input id='password' name='password' type='password'><br>
<input type='submit' value='Login'>
<input type='reset' value='Reset'>
</form>