I'm trying to add comments functionality into my Sails.js blog application. However, I don't seem to write my controller action correctly.
When I submit the comment form, the page starts to reload, but does not finish reloading.
Here's my controller code:
const gravatar = require('gravatar');
module.exports = {
blog: (req, res) => {
Post.find({}).exec((err, posts) => {
if (err) {
res.send(500, { error: 'Database Error' });
}
res.view('all-posts', { posts });
});
},
singlePost: (req, res) => {
Post.findOneBySlug(req.params.slug).exec((err, post) => {
if (err) {
res.send(500, { error: 'Database Error' });
}
res.view('single-post', {
post,
gravatar: gravatar.url
});
});
},
addComment: (req, res) => {
const {
name, comment, email,
url, slug,
} = req.allParams();
Post.findOneBySlug(slug).exec((err, post) => {
if (err) {
return res.send(500, { error: 'Database Error' });
Comment.create({
body: comment, name, email, website: url
}).exec((error, comment) => {
if (error) {
return res.send(500, { error: 'Database Error' });
}
console.log(comment);
post.comments.addComment({slug, comment});
post.save();
res.redirect(`/${slug}`);
});
}
});
return false;
},
};
And here's my routes.js file:
module.exports.routes = {
'get /blog': 'BlogController.blog',
'get /:slug': 'BlogController.singlePost',
'post /:slug/new-comment': 'BlogController.addComment'
};
And this is my model Post.js
module.exports = {
identity: 'Post',
attributes: {
title: {
type: 'string',
required: true,
unique: true
},
body: {
type: 'string'
},
categories: {
type: 'string',
required: true
},
imageUrl: {
type: 'string'
},
comments: {
collection: 'Comment',
via: 'post'
},
slug: {
type: 'slug',
from: 'title',
blacklist: ['search', 'blog', 'contacts']
}
},
addComment: (options, cb) => {
Post.findOneBySlug(options.slug).exec((err, post) => {
if (err) return cb(err);
if (!post) return cb(new Error('Post not found.'));
post.comments.add(options.comment);
post.save(cb);
})
},
connection: 'mongodb'
};
So, when I submit the comment form on the /:slug page, nothing actually happens accept the page tries to reload. And in the database nothing gets saved as well.
The form parameters get sent from the form, so on the client side everything should be fine.
How how I approach this post request correctly?
You need to add return statement before each res.send(500, ...); call, because currently, in the case of the error, your code tries to send the response twice, and client doesn't get the response with the actual error:
if (err) {
return res.send(500, { error: 'Database Error' });
}
... rest code
I suspect, that the reason why nothing is saved in db is invalid parameters in request body.
Related
i am just looking to make an PUT request using Mongoose database. But Its Unable to make any request. I am using postman to pass the data, but no response.
script.js
app.route("/articles/:articleTitle")
.put(function (req, res) {
Article.updateMany(
{ title: req.params.articleTitle },
{ title: req.body.title, content: req.body.content },
{ overwrite: true },
function (err) {
if (!err) {
res.send("Successfully Updated The Data !");
}
}
);
});
here is the code i am using to pass the PUT request in my localhost server but unable to do so.
No Response Here Is The Result
You don't send any response in case of an error, causing the request to hang and never return. Change it to e.g.:
function (err) {
if (!err) {
res.send("Successfully Updated The Data !");
} else {
console.log(err);
res.status(500).send("Update failed due to error " + err.message);
}
}
app.route("/articles/:articleTitle")
.put(async function (req, res) {
try {
await Article.updateMany(
{ title: req.params.articleTitle },
{ title: req.body.title, content: req.body.content },
{ overwrite: true },
)
res.status(200).send("Successfully Updated The Data !");
} catch (err) {
res.status(500).send("Update failed due to error " + err.message);
}
});
I'm using mongoose Model.findOneAndupdate() to find and update my document and there is a post hook on my model schema for which i'm trying to update another document.
The issue i'm facing is post hook is being triggered twice.
My model:
const mongoose = require('mongoose')
const componentSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
component: {
type: String,
required: true
},
message: {
type: String
},
bodyJson: {
type: mongoose.Schema.Types.Mixed
},
question: {
type: String
}
})
componentSchema.post('findOneAndUpdate', function (result) {
console.log('came here')
})
module.exports = mongoose.model('Component', componentSchema)
In my server log i see that came here logged is twice.
update:
try {
await Component.findOneAndUpdate(query, req.body, { new: true }, function (error, doc) {
if (doc) {
return res.status(200).json({ data: doc })
} else if (error) {
return res.status(400).json({ errors: error.message })
} else res.status(404).json({ errors: 'Not found' })
})
} catch (error) {
logger.error('error while updating order: ' + error)
return res.status(400).json({ errors: error.message })
}
moongoose version i'm using is 5.8.11
You are using both await and callback at the same time. This causes the middleware trigger 2 times. Only one of them must be used.
Use either callback:
Component.findOneAndUpdate(query, req.body, { new: true }, function(
error,
doc
) {
if (err) {
return res.status(400).json({ errors: error.message }); //500 status code may be better
} else {
if (doc) {
return res.status(200).json({ data: doc });
} else {
res.status(404).json({ errors: "Not found" });
}
}
});
Or await:
try {
const doc = await Component.findOneAndUpdate(query, req.body, { new: true });
if (doc) {
return res.status(200).json({ data: doc });
} else {
res.status(404).json({ errors: "Not found" });
}
} catch (error) {
logger.error("error while updating order: " + error);
return res.status(400).json({ errors: error.message });
}
I'm working on a small todos app with nodejs and mongodb.
I have the model definition here:
const Todo = new Schema({
text: {
type: String,
require: true,
minlength: 5,
trim: true
},
completed: {
type: Boolean
},
createdAt: {
type: {type: Date, default: Date.now}
}
});
As you can see, the text property is required and it should throw an error if it's missing when it reads the request.
Over here, I'm send the data to my endpoint:
app.post('/todos', (req, res) => {
let todo = new Todo({
text: req.body.text,
completed: req.body.completed
});
todo.save()
.then((document) => {
res.send(document);
}, (error) => {
res.status(400).send(error);
})
});
And finally, this is my test for the specific scenario where the user sends a empty set of data to the server:
it('Should not create todo document with invalid body data', (done) => {
request(app)
.post('/todos')
.send({})
.expect(400)
.end((error, res) => {
if(error){
return done(error);
}
Todo.find()
.then((todos) => {
expect(todos.length).toBe(0);
done();
}).catch((error) => done(error));
});
});
After running the test, for some reason it throws the following:
1) POST /todos
Should not create todo document with invalid body data:
Error: expected 400 "Bad Request", got 200 "OK"
at Test._assertStatus (node_modules\supertest\lib\test.js:266:12)
at Test._assertFunction (node_modules\supertest\lib\test.js:281:11)
at Test.assert (node_modules\supertest\lib\test.js:171:18)
at Server.assert (node_modules\supertest\lib\test.js:131:12)
at emitCloseNT (net.js:1689:8)
at process._tickCallback (internal/process/next_tick.js:152:19)
I've been trying to debug this for the past hour and I can't find what's wrong with it. Can anyone give me a hand?
UPDATE
Other test:
it('Should create a new todo', (done) => {
let text = 'This is a string';
request(app)
.post('/todos')
.send({text})
.expect(200)
.expect((res) => {
let testString = res.body.text;
expect(testString).toBe(text);
expect(typeof testString).toBe('string');
expect(testString.length).not.toBe(0);
})
.end((error, res) => {
if(error) {
return done(error);
}
Todo.find()
.then((todos) => {
expect(todos.length).toBe(1);
expect(todos[0].text).toBe(text);
done();
}).catch((error) => done(error));
});
});
You should check if text and completed exist before using them:
app.post('/todos', (req, res) => {
let text = req.body.text;
let completed = req.body.completed;
if(!completed) { completed = false; }
if(!text) {
res.status(400).send("Request parameters missing");
} else {
let todo = new Todo({
text: req.body.text,
completed: req.body.completed
});
todo.save()
.then((document) => {
res.send(document);
}, (error) => {
res.status(400).send(error);
})
}
});
Also in your Schema it should be "required" instead of "require"
app.put('/edit/:id', function(req, res) {
//new actor data
var actor = {
'name': req.body.name,
'dob': req.body.dob,
'photo': req.file,
'bio' : req.body.bio
};
//updating actor
Actor.findOneAndUpdate({ _id:req.params.id }, { $set: actor }, { new: true }, function(err, data) {
if (err) {
res.send({
status: false,
error: err
});
} else {
res.send({
status: true,
data: data
});
}
});
});
I have tried it with post also and taking id through body also but still it is not working.
Tried it on postman as well as on frontend through form also. In postman also it is not able to take data or read data
Try this in order to update the actor :
Actor.findOneAndUpdate({ _id:req.params.id }, {$set: {actor:actor},}, function(err, data) {
if (err) {
res.send({
status: false,
error: err
});
} else {
res.send({
status: true,
data: data
});
}
});
upsertAsync: function(req, res, next) {
var datas = req.body;
var user = req.body.user;
async.each(datas, function(data, cb) {
sequelize().transaction({
autocommit: true
}, function(t) {
models.Customer.upsert({
id: data.id,
code: data.code,
createdBy: user.name,
modifiedBy: user.name
}, {
transaction: t
}).then(function(customer) {
cb();
}).
catch (function(error) {
t.rollback();
res.status(500).json(error);
});
}, function(err, data) {
log.debug('error (upsertAsync)', err);
if (err) {
t.rollback();
res.status(500).json(err);
}
t.commit();
res.json({
responseCode: '200',
message: 'Customer has been created..!',
data: data
});
});
});
},
I'm using async.each to insert data into sqlite database at the same time. I want to rollback if any error occurs but it shows error which is [TypeError: Cannot set property 'options' of undefined