Frosty CMS: Associating User Data With Comments & Posts
Intro
Continuing our series on Frosty CMS, where we are building a blog CMS from scratch. In the last post we refactored our routes into modules. This time we are going to work on associating users with comments. Currently you must be logged in to make a comment, but the authors name is input manually; a user could put anything in there. We have no way knowing who has posted what. Today we will change that by linking comments to usernames and displaying the usernames automatically.
Comment Associations
Current Comment Schema
Let’s start by taking a look at our current comment schema.
// Mongoose Schema for comments
const commentSchema = new mongoose.Schema({
author: String,
date: {type: Date, default: Date.now},
content: String
});
As we can see the author is being input manually from the comment form as a string.
New Comment Schema
We want to change this to an object that captures the users id and username.
// Mongoose Schema for comments
const commentSchema = new mongoose.Schema({
author: {
id: {
type: mongoose.Schema.Types.ObjectID,
ref: "User"
},
username: String
},
date: {type: Date, default: Date.now},
content: String
});
So we can see here that we have replaced the author string with an object which contains an id and username. And we have specified that the id is a mongoose schema object ID from the User schema.
We have created a place in our comments schema to save the username and id of the user. Now we have to go to the comment route and actually send that data through.
Old Comment Route
Here is the old comment route.
// new comment: receive and save to blog
router.post("/", isLoggedIn, (req,res) => {
// sanitize inputs
req.body.comment.author = req.sanitize(req.body.comment.author);
req.body.comment.content = req.sanitize(req.body.comment.content);
async function saveComment() {
try {
// lookup blog using ID
let blog = await Blog.findById(req.params.id);
// create new comment
let comment = await Comment.create(req.body.comment);
// connect new comment to blog
blog.comments.push(comment);
blog.save();
console.log("New Comment Saved");
// redirect
res.redirect("/blogs/" + blog._id);
} catch(err) {
console.log(err);
}
}
saveComment();
});
What we have to do is, before the comment is pushed to the blog, add the username and id to the comment and save it.
router.post("/", isLoggedIn, (req,res) => {
// sanitize inputs
req.body.comment.content = req.sanitize(req.body.comment.content);
async function saveComment() {
try {
// lookup blog using ID
let blog = await Blog.findById(req.params.id);
// create new comment
let comment = await Comment.create(req.body.comment);
// add username and id to comment
comment.author.id = req.user._id;
comment.author.username = req.user.username
// save comment
comment.save();
// connect new comment to blog
blog.comments.push(comment);
blog.save();
console.log("New Comment: " + comment);
// redirect
res.redirect("/blogs/" + blog._id);
} catch(err) {
console.log(err);
}
}
saveComment();
});
And we can see that the username and id has been captured in the comment in an object called author.
Updating Comment Display Template
The last thing to do is that we need to update our comment display partial, which is the easiest part. We just add .username to the end of comment.author.
<!--Comments Loop -->
<% blog.comments.forEach((comment) => { %>
<p><strong><%= comment.author.username %></strong><em class="text-muted"> - <%= comment.date.toDateString() %></em></p>
<p><%= comment.content %></p>
<% }); %>
That’s all done. Now we just need to follow the (basically) same process for new blogs.
Blogs
The primary difference here is how we handle the route. Here is the refactor of the new blog route. We have broken all the incoming pieces of information into a new temporary variable and then combined them all into one variable called newBlog which we then push into Blog.create.
// new blog: receive and save
router.post("/", isLoggedIn, (req, res) => {
// sanitize inputs
req.body.blog.title = req.sanitize(req.body.blog.title);
req.body.blog.short = req.sanitize(req.body.blog.short);
req.body.blog.content = req.sanitize(req.body.blog.content);
// assign variables to incoming data
let title = req.body.blog.title,
image = req.body.blog.image,
short = req.body.blog.short,
content = req.body.blog.content,
date = req.body.blog.date;
// retriever user data
let author = {
id: req.user._id,
username: req.user.username,
firstname: req.user.firstname,
lastname: req.user.lastname
};
// combine all data into new variable
let newBlog = {title: title, image: image, short: short, content: content, date: date, author: author};
// save combined data to new blog
Blog.create(newBlog,(err, newDatabaseRecord) => {
if(err){
console.log("Failed to write post to database.");
} else {
console.log("Blog successfully saved to database.");
console.log(newDatabaseRecord);
// redirect back to blogs page
res.redirect("/");
}
});
});
});
GitHub Repo
Comments
Recent Work
Basalt
basalt.softwareFree desktop AI Chat client, designed for developers and businesses. Unlocks advanced model settings only available in the API. Includes quality of life features like custom syntax highlighting.
BidBear
bidbear.ioBidbear is a report automation tool. It downloads Amazon Seller and Advertising reports, daily, to a private database. It then merges and formats the data into beautiful, on demand, exportable performance reports.